diff options
-rw-r--r-- | bdep/new.cli | 93 | ||||
-rw-r--r-- | bdep/new.cxx | 709 | ||||
-rw-r--r-- | bdep/utility.cxx | 16 | ||||
-rw-r--r-- | tests/new.testscript | 74 |
4 files changed, 575 insertions, 317 deletions
diff --git a/bdep/new.cli b/bdep/new.cli index c7e7fcb..1e25a52 100644 --- a/bdep/new.cli +++ b/bdep/new.cli @@ -26,7 +26,8 @@ namespace bdep \b{bdep new} [<options>] \b{--config-add|-A} <cfg-dir> [\b{@}<cfg-name>] <spec> <name>\n \b{bdep new} [<options>] \b{--config-create|-C} <cfg-dir> [\b{@}<cfg-name>] <spec> <name>\n \ \ \ \ \ \ \ \ \ [<cfg-args>]\n - \b{bdep new} [<options>] \b{--package} [<prj-spec>] <spec> <name>} + \b{bdep new} [<options>] \b{--package} [<prj-spec>] <spec> <name>\n + \b{bdep new} [<options>] \b{--subdirectory} [<prj-spec>] <spec> <name>} \c{<spec> \ \ \ \ = [<type>] [<lang>] [<vcs>]\n <type> \ \ \ \ = \b{--type}|\b{-t} (\b{exe}|\b{lib}|\b{bare}|\b{empty})[\b{,}<type-opt>...]\n @@ -38,8 +39,10 @@ namespace bdep \h|DESCRIPTION| The \cb{new} command creates and initializes a new project (the first - three forms) or a new package in an already existing project (the last - form). All four forms first create according to <spec> a new \cb{build2} + three forms), a new package in an already existing project (the + \cb{--package} form), or a new source subdirectory in an already existing + project/package (the \cb{--subdirectory} form). All the forms except + \cb{--subdirectory} first create according to <spec> a new \cb{build2} project/package called <name> in the <name> subdirectory of the current working directory (unless overridden with \c{\b{--output-dir}|\b{-o}}). See \l{bpkg#package-name Package Name} for details on project/package @@ -47,16 +50,60 @@ namespace bdep The first form then, unless the \cb{--no-init} option is specified, initializes an empty project database as if by executing the - \l{bdep-init(1)} command with the \cb{--empty} option. Similarly, the - second and third forms add an existing or create new build configuration - and then initialize the project in that configuration as if by executing - the \l{bdep-init(1)} command with the \cb{--config-add} or - \cb{--config-create} option, respectively. + \l{bdep-init(1)} command with the \cb{--empty} option. For example: - The last form adds the new package to the \cb{packages.manifest} file - creating it if necessary. If no project directory is explicitly specified - with \c{\b{--directory}|\b{-d}}, then the current working directory is - assumed. Note that nested packages are not allowed. + \ + $ bdep new -t exe -l c++ hello + \ + + Similarly, the second and third forms add an existing or create new build + configuration and then initialize the project in that configuration as if + by executing the \l{bdep-init(1)} command with the \cb{--config-add} or + \cb{--config-create} option, respectively. For example: + + \ + $ bdep new -t exe -l c++ -C @gcc hello cc config.cxx=g++ + \ + + The \cb{--package} form adds the new package to the + \cb{packages.manifest} file creating it if necessary. If no project + directory is explicitly specified with \c{\b{--directory}|\b{-d}}, then + the current working directory is assumed. Note that nested packages are + not allowed. For example: + + \ + $ bdep new -t empty hello + $ cd hello + + $ bdep new --package -t lib -l c++ libhello + $ bdep new --package -t exe -l c++ hello + + $ bdep init -C @gcc cc config.cxx=g++ + \ + + After executing these commands the \c{hello} project will contains + two packages, \c{libhello} and \c{hello}. + + The \cb{--subdirectory} form operates \i{as-if} by first creating + according to <spec> a temporary project called <name> and then copying + its source subdirectory (\c{\i{name}\b{/}\i{name}\b{/}}) over to the + current working directory (unless overridden with + \c{\b{--output-dir}|\b{-o}}). If no project/package directory is + explicitly specified with \c{\b{--directory}|\b{-d}}, then the current + working directory is assumed. For example: + + \ + $ bdep new -t bare hello + $ cd hello + + $ bdep new --subdirectory -t lib -l c++ libhello + $ bdep new --subdirectory -t exe -l c++ hello + + $ bdep init -C @gcc cc config.cxx=g++ + \ + + After executing these commands the \c{hello} project will contains two + source subdirectories, \c{libhello/} and \c{hello/}. The project parameters such as type (executable, library, etc), language, and version control system can be customized as described next. Some of @@ -91,12 +138,15 @@ namespace bdep \cb{unit-tests} \- Add support for unit testing. + \cb{no-version} \- Don't add support for generating the version header. + \cb{alt-naming} \- Use the alternative build file/directory naming scheme. | \li|\cb{bare} - A project without any source code. Recognized bare project options: + A project without any source code that can be filled later (see + \cb{--subdirectory}). Recognized bare project options: \cb{no-tests} \- Don't add support for testing. @@ -162,6 +212,7 @@ namespace bdep { bool no-tests; bool unit-tests; + bool no-version; bool alt-naming; }; @@ -209,21 +260,29 @@ namespace bdep bool --package { - "Create a package inside an already existing project rather than a + "Create a new package inside an already existing project rather than a new project." } + bool --subdirectory + { + "Create a new source subdirectory inside an already existing project or + package rather than a new project." + } + dir_path --output-dir|-o { "<dir>", - "Create the project in the specified directory." + "Create the project, package, or source subdirectory in the specified + directory." } dir_path --directory|-d { "<dir>", - "Assume the project is in the specified directory rather than in the - current working directory. Only used with \cb{--package}." + "Assume the project/package is in the specified directory rather than + in the current working directory. Only used with \cb{--package} or + \cb{--subdirectory}." } cmd_new_type --type|-t diff --git a/bdep/new.cxx b/bdep/new.cxx index 37fd235..a1292d3 100644 --- a/bdep/new.cxx +++ b/bdep/new.cxx @@ -34,18 +34,24 @@ namespace bdep bool ca (o.config_add_specified ()); bool cc (o.config_create_specified ()); - if (o.package () && o.no_init ()) - fail << "both --no-init and --package specified"; + if (o.package () && o.subdirectory ()) + fail << "both --package and --subdirectory specified"; + + const char* m (o.package () ? "--package" : + o.subdirectory () ? "--subdirectory" : nullptr); + + if (m && o.no_init ()) + fail << "both --no-init and " << m << " specified"; if (const char* n = (o.no_init () ? "--no-init" : - o.package () ? "--package" : nullptr)) + m ? m : nullptr)) { if (ca) fail << "both " << n << " and --config-add specified"; if (cc) fail << "both " << n << " and --config-create specified"; } - if (o.directory_specified () && !o.package ()) - fail << "--directory|-d only valid with --package"; + if (o.directory_specified () && !m) + fail << "--directory|-d only valid with --package or --subdirectory"; if (const char* n = cmd_config_validate_add (o)) { @@ -60,9 +66,16 @@ namespace bdep // const type& t (o.type ()); - bool altn (false); // alt-naming + // For a library source subdirectory (--subdirectory) we don't generate + // the export stub, integration tests (because there is no export stub), + // or the version header (because the project name used in the .in file + // will most likely be wrong). All this seems reasonable for what this + // mode is expected to be used ("end-product" kind of projects). + // + bool altn (false); // alt-naming bool itest (false); // !no-tests bool utest (false); // unit-tests + bool ver (false); // !no-version switch (t) { @@ -76,18 +89,26 @@ namespace bdep case type::lib: { altn = t.lib_opt.alt_naming (); - itest = !t.lib_opt.no_tests (); + itest = !t.lib_opt.no_tests () && !o.subdirectory (); utest = t.lib_opt.unit_tests (); + ver = !t.lib_opt.no_version () && !o.subdirectory (); break; } case type::bare: { + if (o.subdirectory ()) + fail << "cannot create bare source subdirectory"; + altn = t.bare_opt.alt_naming (); itest = !t.bare_opt.no_tests (); break; } case type::empty: { + if (const char* w = (o.subdirectory () ? "source subdirectory" : + o.package () ? "package" : nullptr)) + fail << "cannot create empty " << w; + break; } } @@ -155,37 +176,44 @@ namespace bdep // base name for inner filesystem directories and preprocessor macros, // while the (sanitized) stem for modules, namespaces, etc. // - const string& n (pkgn.string ()); - const string& b (pkgn.base ()); - const string& v (pkgn.variable ()); - - string s (b); - switch (t) + const string& n (pkgn.string ()); // Full name. + const string& b (pkgn.base ()); // Base name. + const string& v (pkgn.variable ()); // Variable name. + string s (b); // Name stem. { - case type::exe: - { - if (s.compare (0, 3, "lib") == 0) - warn << "executable name starts with 'lib'"; + // Warn about the lib prefix unless we are creating a source + // subdirectory, in which case the project is probably not meant to be a + // package anyway. + // + bool w (!o.subdirectory ()); - break; - } - case type::lib: + switch (t) { - if (s.compare (0, 3, "lib") == 0) + case type::exe: { - s.erase (0, 3); + if (w && s.compare (0, 3, "lib") == 0) + warn << "executable name starts with 'lib'"; - if (s.empty ()) - fail << "empty library name stem in '" << b << "'"; + break; } - else - warn << "library name does not start with 'lib'"; + case type::lib: + { + if (s.compare (0, 3, "lib") == 0) + { + s.erase (0, 3); + + if (w && s.empty ()) + fail << "empty library name stem in '" << b << "'"; + } + else if (w) + warn << "library name does not start with 'lib'"; + break; + } + case type::bare: + case type::empty: break; } - case type::bare: - case type::empty: - break; } // Sanitize the stem to be a valid language identifier. @@ -206,11 +234,13 @@ namespace bdep } } - dir_path out; // Project/package output directory. + dir_path out; // Project/package/subdirectory output directory. dir_path prj; // Project. optional<dir_path> pkg; // Package relative to its project root. + optional<dir_path> sub; // Source subdirectory relative to its + // project/package root. - if (o.package ()) + if (o.package () || o.subdirectory ()) { if (o.directory_specified ()) (prj = o.directory ()).complete ().normalize (); @@ -220,11 +250,35 @@ namespace bdep out = o.output_dir_specified () ? o.output_dir () : prj / dir_path (n); out.complete ().normalize (); - if (!out.sub (prj)) - fail << "package directory " << out << " is not a subdirectory of " - << "project directory " << prj; + if (o.package ()) + { + if (!out.sub (prj)) + fail << "package directory " << out << " is not a subdirectory of " + << "project directory " << prj; - pkg = out.leaf (prj); + pkg = out.leaf (prj); + } + else if (o.subdirectory ()) + { + if (!out.sub (prj)) + fail << "source subdirectory " << out << " is not a subdirectory of " + << "project/package directory " << prj; + + // We use this information to form the include directories. The idea + // is that if the user places the subdirectory somewhere deeper (say + // into core/libfoo/), then we want the include directives to contain + // the prefix from the project root (so it will be <core/libfoo/...>) + // since all our buildfiles are hardwired with -I$src_root. + // + // Note also that a crafty user can adjust the prefix by picking the + // appropriate --directory|-d (i.e., it can point somewhere deeper + // than the project root). They will need to adjust their buildfiles, + // however (or we could get smarter by finding the actual package root + // and adding the difference to -I). Also, some other things, such as + // the namespace, currently do not contain the prefix. + // + sub = out.leaf (prj); + } } else { @@ -233,6 +287,10 @@ namespace bdep prj = out; } + // Source directory relative to package root. + // + const dir_path& d (sub ? *sub : dir_path (b)); + // Create the output directory and do some sanity check (empty if exists, // nested packages, etc; you would be surprised what people come up with). // @@ -242,7 +300,7 @@ namespace bdep if (e && !empty (out)) fail << "directory " << out << " already exists and is not empty"; - if (!o.no_checks ()) + if (!o.no_checks () && !sub) { project_package pp ( find_project_package (out, true /* ignore_not_found */)); @@ -273,14 +331,14 @@ namespace bdep } if (!e) - mk (out); + mk_p (out); } // Initialize the version control system. Do it before writing anything // ourselves in case it fails. Also, the email discovery may do the VCS // detection. // - if (!pkg) + if (!pkg && !sub) { switch (vc) { @@ -298,40 +356,43 @@ namespace bdep // // See also tests/.gitignore below. // - if (vc == vcs::git) + if (!sub) { - // Use POSIX directory separators here. - // - os.open (f = out / ".gitignore"); - if (!pkg) - os << bdep_dir.posix_representation () << endl - << endl; - if (t != type::empty) - os << "# Compiler/linker output." << endl - << "#" << endl - << "*.d" << endl - << "*.t" << endl - << "*.i" << endl - << "*.ii" << endl - << "*.o" << endl - << "*.obj" << endl - << "*.so" << endl - << "*.dll" << endl - << "*.a" << endl - << "*.lib" << endl - << "*.exp" << endl - << "*.pdb" << endl - << "*.ilk" << endl - << "*.exe" << endl - << "*.exe.dlls/" << endl - << "*.exe.manifest" << endl - << "*.pc" << endl; - os.close (); + if (vc == vcs::git) + { + // Use POSIX directory separators here. + // + os.open (f = out / ".gitignore"); + if (!pkg) + os << bdep_dir.posix_representation () << endl + << endl; + if (t != type::empty) + os << "# Compiler/linker output." << endl + << "#" << endl + << "*.d" << endl + << "*.t" << endl + << "*.i" << endl + << "*.ii" << endl + << "*.o" << endl + << "*.obj" << endl + << "*.so" << endl + << "*.dll" << endl + << "*.a" << endl + << "*.lib" << endl + << "*.exp" << endl + << "*.pdb" << endl + << "*.ilk" << endl + << "*.exe" << endl + << "*.exe.dlls/" << endl + << "*.exe.manifest" << endl + << "*.pc" << endl; + os.close (); + } } // repositories.manifest // - if (!pkg) + if (!pkg && !sub) { os.open (f = out / "repositories.manifest"); os << ": 1" << endl @@ -349,7 +410,7 @@ namespace bdep } // packages.manifest // - else + else if (!sub) { bool e (exists (f = prj / "packages.manifest")); os.open (f, fdopen_mode::create | fdopen_mode::append); @@ -363,95 +424,70 @@ namespace bdep // manifest // - - // Project name. - // - // If this is a package in a project (--package mode), then use the - // project directory name as the project name. Otherwise, the project - // name is the same as the package and is therefore omitted. - // - // In case of a library, we could have used either the full name or the - // stem without the lib prefix. And it could go either way: if a library - // is (likely to be) accompanied by an executable (or some other extra - // packages), then its project should probably be the stem. Otherwise, - // if it is a standalone library, then the full library name is probably - // preferred. The stem also has another problem: it could be an invalid - // project name. So using the full name seems like a simpler and more - // robust approach. - // - // There was also an idea to warn if the project name ends with a digit - // (think libfoo and libfoo2). - // - optional<project_name> prjn; - - if (o.package ()) + if (!sub) { - string p (prj.leaf ().string ()); - - if (p != n) // Omit if the same as the package name. + // Project name. + // + // If this is a package in a project (--package mode), then use the + // project directory name as the project name. Otherwise, the project + // name is the same as the package and is therefore omitted. + // + // In case of a library, we could have used either the full name or + // the stem without the lib prefix. And it could go either way: if a + // library is (likely to be) accompanied by an executable (or some + // other extra packages), then its project should probably be the + // stem. Otherwise, if it is a standalone library, then the full + // library name is probably preferred. The stem also has another + // problem: it could be an invalid project name. So using the full + // name seems like a simpler and more robust approach. + // + // There was also an idea to warn if the project name ends with a + // digit (think libfoo and libfoo2). + // + optional<project_name> pn; + if (pkg) { - try - { - prjn = project_name (move (p)); - } - catch (const invalid_argument& e) + string p (prj.leaf ().string ()); + + if (p != n) // Omit if the same as the package name. { - warn << "project name '" << p << "' is invalid: " << e << - info << "leaving the 'project' manifest value empty"; + try + { + pn = project_name (move (p)); + } + catch (const invalid_argument& e) + { + warn << "project name '" << p << "' is invalid: " << e << + info << "leaving the 'project' manifest value empty"; - prjn = project_name (); + pn = project_name (); + } } } - } - - // Project email. - // - string email; - { - optional<string> r (find_project_author_email (prj)); - email = r ? move (*r) : "you@example.org"; - } - os.open (f = out / "manifest"); - os << ": 1" << endl - << "name: " << n << endl - << "version: 0.1.0-a.0.z" << endl; - if (prjn) - os << "project: " << *prjn << endl; - os << "summary: " << s << " " << t << endl - << "license: TODO" << endl - << "url: https://example.org/" << (prjn ? prjn->string () : n) << endl - << "email: " << email << endl - << "depends: * build2 >= 0.9.0-" << endl - << "depends: * bpkg >= 0.9.0-" << endl - << "#depends: libhello ^1.0.0" << endl; - os.close (); - - // build/ - // - dir_path bd (dir_path (out) / build_dir); - mk (bd); + // Project email. + // + string pe; + { + optional<string> r (find_project_author_email (prj)); + pe = r ? move (*r) : "you@example.org"; + } - // build/bootstrap.build - // - os.open (f = bd / "bootstrap." + build_ext); - os << "project = " << n << endl; - if (o.no_amalgamation ()) - os << "amalgamation = # Disabled." << endl; - os << endl - << "using version" << endl - << "using config" << endl; - if (itest || utest) - os << "using test" << endl; - os << "using install" << endl - << "using dist" << endl; - os.close (); - - // build/root.build - // - // Note: see also tests/build/root.build below. - // - os.open (f = bd / "root." + build_ext); + os.open (f = out / "manifest"); + os << ": 1" << endl + << "name: " << n << endl + << "version: 0.1.0-a.0.z" << endl; + if (pn) + os << "project: " << *pn << endl; + os << "summary: " << s << " " << t << endl + << "license: TODO" << endl + << "url: https://example.org/" << (pn ? pn->string () : n) << endl + << "email: " << pe << endl + << "depends: * build2 >= 0.9.0-" << endl + << "depends: * bpkg >= 0.9.0-" << endl + << "#depends: libhello ^1.0.0" << endl; + os.close (); + } string m; // Language module. string x; // Source target type. @@ -467,15 +503,6 @@ namespace bdep x = "c"; h = "h"; hs = "h"; - - // @@ TODO: 'latest' in c.std. - // - os //<< "c.std = latest" << endl - //<< endl - << "using c" << endl - << endl - << "h{*}: extension = h" << endl - << "c{*}: extension = c" << endl; break; } case lang::cxx: @@ -485,55 +512,107 @@ namespace bdep h = "hxx"; hs = "hxx ixx txx"; es = l.cxx_opt.cpp () ? "pp" : "xx"; - - os << "cxx.std = latest" << endl - << endl - << "using cxx" << endl - << endl - << "hxx{*}: extension = h" << es << endl - << "ixx{*}: extension = i" << es << endl - << "txx{*}: extension = t" << es << endl - << "cxx{*}: extension = c" << es << endl; break; } } - if ((itest || utest) && !m.empty ()) - os << endl - << "# The test target for cross-testing (running tests under Wine, etc)." << endl - << "#" << endl - << "test.target = $" << m << ".target" << endl; - - os.close (); - - // build/.gitignore + // build/ // - if (vc == vcs::git) + dir_path bd; + if (!sub) { - os.open (f = bd / ".gitignore"); - os << "config." << build_ext << endl - << "root/" << endl - << "bootstrap/" << endl; + bd = out / build_dir; + mk (bd); + + // build/bootstrap.build + // + os.open (f = bd / "bootstrap." + build_ext); + os << "project = " << n << endl; + if (o.no_amalgamation ()) + os << "amalgamation = # Disabled." << endl; + os << endl + << "using version" << endl + << "using config" << endl; + if (itest || utest) + os << "using test" << endl; + os << "using install" << endl + << "using dist" << endl; os.close (); + + // build/root.build + // + // Note: see also tests/build/root.build below. + // + os.open (f = bd / "root." + build_ext); + + switch (l) + { + case lang::c: + { + // @@ TODO: 'latest' in c.std. + // + // << "c.std = latest" << endl + // << endl + os << "using c" << endl + << endl + << "h{*}: extension = h" << endl + << "c{*}: extension = c" << endl; + break; + } + case lang::cxx: + { + os << "cxx.std = latest" << endl + << endl + << "using cxx" << endl + << endl + << "hxx{*}: extension = h" << es << endl + << "ixx{*}: extension = i" << es << endl + << "txx{*}: extension = t" << es << endl + << "cxx{*}: extension = c" << es << endl; + break; + } + } + + if ((itest || utest) && !m.empty ()) + os << endl + << "# The test target for cross-testing (running tests under Wine, etc)." << endl + << "#" << endl + << "test.target = $" << m << ".target" << endl; + + os.close (); + + // build/.gitignore + // + if (vc == vcs::git) + { + os.open (f = bd / ".gitignore"); + os << "config." << build_ext << endl + << "root/" << endl + << "bootstrap/" << endl; + os.close (); + } } // buildfile // - os.open (f = out / buildfile_file); - os << "./: {*/ -" << build_dir.posix_representation () << "} manifest" << endl; - if (itest && t == type::lib) // Have tests/ subproject. - os << endl - << "# Don't install tests." << endl - << "#" << endl - << "tests/: install = false" << endl; - os.close (); + if (!sub) + { + os.open (f = out / buildfile_file); + os << "./: {*/ -" << build_dir.posix_representation () << "} manifest" << endl; + if (itest && t == type::lib) // Have tests/ subproject. + os << endl + << "# Don't install tests." << endl + << "#" << endl + << "tests/: install = false" << endl; + os.close (); + } if (t == type::bare) break; // <base>/ (source subdirectory). // - dir_path sd (dir_path (out) /= b); + const dir_path& sd (sub ? out : out / d); mk (sd); switch (t) @@ -715,34 +794,38 @@ namespace bdep } case type::lib: { + string ip (d.posix_representation ()); // Include prefix. + string mp; // Macro prefix. transform ( - b.begin (), b.end (), back_inserter (mp), + ip.begin (), ip.end () - 1, back_inserter (mp), [] (char c) { - return (c == '-' || c == '+' || c == '.') ? '_' : ucase (c); + return (c == '-' || c == '+' || c == '.' || c == '/') + ? '_' + : ucase (c); }); - string hdr; // API header name. - string exp; // Export header name (empty if binless). - string ver; // Version header name. + string apih; // API header name. + string exph; // Export header name (empty if binless). + string verh; // Version header name. switch (l) { case lang::c: { - hdr = s + ".h"; - exp = "export.h"; - ver = "version.h"; + apih = s + ".h"; + exph = "export.h"; + verh = ver ? "version.h" : string (); // <stem>.h // - os.open (f = sd / hdr); + os.open (f = sd / apih); os << "#pragma once" << endl << endl << "#include <stdio.h>" << endl << endl - << "#include <" << b << "/" << exp << ">" << endl + << "#include <" << ip << exph << ">" << endl << endl << "// Print a greeting for the specified name into the specified" << endl << "// stream. On success, return the number of character printed." << endl @@ -755,7 +838,7 @@ namespace bdep // <stem>.c // os.open (f = sd / s + ".c"); - os << "#include <" << b << "/" << hdr << ">" << endl + os << "#include <" << ip << apih << ">" << endl << endl << "#include <errno.h>" << endl << endl @@ -776,12 +859,12 @@ namespace bdep case lang::cxx: if (l.cxx_opt.binless ()) { - hdr = s + ".h" + es; - ver = "version.h" + es; + apih = s + ".h" + es; + verh = ver ? "version.h" + es : string (); // <stem>.h(xx|pp) // - os.open (f = sd / hdr); + os.open (f = sd / apih); os << "#pragma once" << endl << endl << "#include <string>" << endl @@ -810,19 +893,19 @@ namespace bdep } else { - hdr = s + ".h" + es; - exp = "export.h" + es; - ver = "version.h" + es; + apih = s + ".h" + es; + exph = "export.h" + es; + verh = ver ? "version.h" + es : string (); // <stem>.h(xx|pp) // - os.open (f = sd / hdr); + os.open (f = sd / apih); os << "#pragma once" << endl << endl << "#include <iosfwd>" << endl << "#include <string>" << endl << endl - << "#include <" << b << "/" << exp << ">" << endl + << "#include <" << ip << exph << ">" << endl << endl << "namespace " << id << endl << "{" << endl @@ -837,7 +920,7 @@ namespace bdep // <stem>.c(xx|pp) // os.open (f = sd / s + ".c" + es); - os << "#include <" << b << "/" << hdr << ">" << endl + os << "#include <" << ip << apih << ">" << endl << endl << "#include <ostream>" << endl << "#include <stdexcept>" << endl @@ -862,9 +945,9 @@ namespace bdep // export.h[??] // - if (!exp.empty ()) + if (!exph.empty ()) { - os.open (f = sd / exp); + os.open (f = sd / exph); os << "#pragma once" << endl << endl; if (l == lang::cxx) @@ -907,42 +990,45 @@ namespace bdep // version.h[??].in // - os.open (f = sd / ver + ".in"); + if (ver) + { + os.open (f = sd / verh + ".in"); - os << "#pragma once" << endl - << endl - << "// The numeric version format is AAABBBCCCDDDE where:"<< endl - << "//" << endl - << "// AAA - major version number" << endl - << "// BBB - minor version number" << endl - << "// CCC - bugfix version number" << endl - << "// DDD - alpha / beta (DDD + 500) version number" << endl - << "// E - final (0) / snapshot (1)" << endl - << "//" << endl - << "// When DDDE is not 0, 1 is subtracted from AAABBBCCC. For example:" << endl - << "//" << endl - << "// Version AAABBBCCCDDDE" << endl - << "//" << endl - << "// 0.1.0 0000010000000" << endl - << "// 0.1.2 0000010010000" << endl - << "// 1.2.3 0010020030000" << endl - << "// 2.2.0-a.1 0020019990010" << endl - << "// 3.0.0-b.2 0029999995020" << endl - << "// 2.2.0-a.1.z 0020019990011" << endl - << "//" << endl - << "#define " << mp << "_VERSION $" << v << ".version.project_number$ULL" << endl - << "#define " << mp << "_VERSION_STR \"$" << v << ".version.project$\"" << endl - << "#define " << mp << "_VERSION_ID \"$" << v << ".version.project_id$\"" << endl - << endl - << "#define " << mp << "_VERSION_MAJOR $" << v << ".version.major$" << endl - << "#define " << mp << "_VERSION_MINOR $" << v << ".version.minor$" << endl - << "#define " << mp << "_VERSION_PATCH $" << v << ".version.patch$" << endl - << endl - << "#define " << mp << "_PRE_RELEASE $" << v << ".version.pre_release$" << endl - << endl - << "#define " << mp << "_SNAPSHOT_SN $" << v << ".version.snapshot_sn$ULL" << endl - << "#define " << mp << "_SNAPSHOT_ID \"$" << v << ".version.snapshot_id$\"" << endl; - os.close (); + os << "#pragma once" << endl + << endl + << "// The numeric version format is AAABBBCCCDDDE where:"<< endl + << "//" << endl + << "// AAA - major version number" << endl + << "// BBB - minor version number" << endl + << "// CCC - bugfix version number" << endl + << "// DDD - alpha / beta (DDD + 500) version number" << endl + << "// E - final (0) / snapshot (1)" << endl + << "//" << endl + << "// When DDDE is not 0, 1 is subtracted from AAABBBCCC. For example:" << endl + << "//" << endl + << "// Version AAABBBCCCDDDE" << endl + << "//" << endl + << "// 0.1.0 0000010000000" << endl + << "// 0.1.2 0000010010000" << endl + << "// 1.2.3 0010020030000" << endl + << "// 2.2.0-a.1 0020019990010" << endl + << "// 3.0.0-b.2 0029999995020" << endl + << "// 2.2.0-a.1.z 0020019990011" << endl + << "//" << endl + << "#define " << mp << "_VERSION $" << v << ".version.project_number$ULL" << endl + << "#define " << mp << "_VERSION_STR \"$" << v << ".version.project$\"" << endl + << "#define " << mp << "_VERSION_ID \"$" << v << ".version.project_id$\"" << endl + << endl + << "#define " << mp << "_VERSION_MAJOR $" << v << ".version.major$" << endl + << "#define " << mp << "_VERSION_MINOR $" << v << ".version.minor$" << endl + << "#define " << mp << "_VERSION_PATCH $" << v << ".version.patch$" << endl + << endl + << "#define " << mp << "_PRE_RELEASE $" << v << ".version.pre_release$" << endl + << endl + << "#define " << mp << "_SNAPSHOT_SN $" << v << ".version.snapshot_sn$ULL"<< endl + << "#define " << mp << "_SNAPSHOT_ID \"$" << v << ".version.snapshot_id$\"" << endl; + os.close (); + } bool binless (l == lang::cxx && l.cxx_opt.binless ()); @@ -957,24 +1043,36 @@ namespace bdep if (!utest) { os << "lib{" << s << "}: " << - "{" << hs << (binless ? "" : ' ' + x) << "}" << - "{** -version} " << - h << "{version} $imp_libs $int_libs" << endl; + "{" << hs << (binless ? "" : ' ' + x) << "}{**"; + if (ver) + os << " -version} " << h << "{version}"; + else + os << "}"; + os << " $imp_libs $int_libs" << endl; } else { if (binless) { os << "./: lib{" << s << "}: " << - "{" << hs << "}{** -version -**.test...} " << - h << "{version} \\" << endl - << " $imp_libs $int_libs" << endl; + "{" << hs << "}{** -**.test..."; + if (ver) + os << " -version} " << h << "{version} \\" << endl + << " "; + else + os << "}"; + os << " $imp_libs $int_libs" << endl; } else { os << "./: lib{" << s << "}: libul{" << s << "}: " << - "{" << hs << ' ' << x << "}{** -version -**.test...} \\" << endl - << " " << h << "{version} $imp_libs $int_libs" << endl; + "{" << hs << ' ' << x << "}{** -**.test..."; + if (ver) + os << " -version} \\" << endl + << " " << h << "{version}"; + else + os << "}"; + os << " $imp_libs $int_libs" << endl; } os << endl @@ -1002,17 +1100,18 @@ namespace bdep os << "}" << endl; } - os << endl - << "# Include the generated version header into the distribution (so that we don't" << endl - << "# pick up an installed one) and don't remove it when cleaning in src (so that" << endl - << "# clean results in a state identical to distributed)." << endl - << "#" << endl - << h << "{version}: in{version} $src_root/manifest" << endl - << h << "{version}:" << endl - << "{" << endl - << " dist = true" << endl - << " clean = ($src_root != $out_root)" << endl - << "}" << endl; + if (ver) + os << endl + << "# Include the generated version header into the distribution (so that we don't" << endl + << "# pick up an installed one) and don't remove it when cleaning in src (so that" << endl + << "# clean results in a state identical to distributed)." << endl + << "#" << endl + << h << "{version}: in{version} $src_root/manifest" << endl + << h << "{version}:" << endl + << "{" << endl + << " dist = true" << endl + << " clean = ($src_root != $out_root)" << endl + << "}" << endl; // Build. // @@ -1058,32 +1157,36 @@ namespace bdep // Installation. // os << endl - << "# Install into the " << b << "/ subdirectory of, say, /usr/include/" << endl + << "# Install into the " << ip << " subdirectory of, say, /usr/include/" << endl << "# recreating subdirectories." << endl << "#" << endl << "{" << hs << "}{*}:" << endl << "{" << endl - << " install = include/" << b << "/" << endl + << " install = include/" << ip << endl << " install.subdirs = true" << endl << "}" << endl; os.close (); // <base>/.gitignore // - if (vc == vcs::git) + if (ver || utest) { - os.open (f = sd / ".gitignore"); - os << "# Generated version header." << endl - << "#" << endl - << ver << endl; - if (utest) - os << endl - << "# Unit test executables and Testscript output directories" << endl - << "# (can be symlinks)." << endl - << "#" << endl - << "*.test" << endl - << "test-*.test" << endl; - os.close (); + if (vc == vcs::git) + { + os.open (f = sd / ".gitignore"); + if (ver) + os << "# Generated version header." << endl + << "#" << endl + << verh << endl; + if (utest) + os << (ver ? "\n" : "") + << "# Unit test executables and Testscript output directories" << endl + << "# (can be symlinks)." << endl + << "#" << endl + << "*.test" << endl + << "test-*.test" << endl; + os.close (); + } } // <base>/<stem>.test.* @@ -1100,7 +1203,7 @@ namespace bdep os << "#include <stdio.h>" << endl << "#include <assert.h>" << endl << endl - << "#include <" << b << "/" << hdr << ">" << endl + << "#include <" << ip << apih << ">" << endl << endl << "int main ()" << endl << "{" << endl @@ -1118,7 +1221,7 @@ namespace bdep os << "#include <cassert>" << endl << "#include <iostream>" << endl << endl - << "#include <" << b << "/" << hdr << ">" << endl + << "#include <" << ip << apih << ">" << endl << endl << "int main ()" << endl << "{" << endl @@ -1133,14 +1236,17 @@ namespace bdep // build/export.build // - os.open (f = bd / "export." + build_ext); - os << "$out_root/" << endl - << "{" << endl - << " include " << b << "/" << endl - << "}" << endl - << endl - << "export $out_root/" << b << "/$import.target" << endl; - os.close (); + if (!sub) + { + os.open (f = bd / "export." + build_ext); + os << "$out_root/" << endl + << "{" << endl + << " include " << ip << endl + << "}" << endl + << endl + << "export $out_root/" << ip << "$import.target" << endl; + os.close (); + } // tests/ (tests subproject). // @@ -1254,9 +1360,10 @@ namespace bdep << "#include <errno.h>" << endl << "#include <string.h>" << endl << "#include <assert.h>" << endl - << endl - << "#include <" << b << "/" << ver << ">" << endl - << "#include <" << b << "/" << hdr << ">" << endl + << endl; + if (ver) + os << "#include <" << ip << verh << ">" << endl; + os << "#include <" << ip << apih << ">" << endl << endl << "int main ()" << endl << "{" << endl @@ -1293,9 +1400,10 @@ namespace bdep os << "#include <cassert>" << endl << "#include <sstream>" << endl << "#include <stdexcept>" << endl - << endl - << "#include <" << b << "/" << ver << ">" << endl - << "#include <" << b << "/" << hdr << ">" << endl + << endl; + if (ver) + os << "#include <" << ip << verh << ">" << endl; + os << "#include <" << ip << apih << ">" << endl << endl << "int main ()" << endl << "{" << endl @@ -1357,12 +1465,13 @@ namespace bdep } if (verb) - text << "created new " << t << ' ' << (pkg ? "package" : "project") + text << "created new " << t << ' ' << (sub ? "source subdirectory" : + pkg ? "package" : "project") << ' ' << n << " in " << out; - // --no-init | --package + // --no-init | --package | --subdirectory // - if (o.no_init () || o.package ()) + if (o.no_init () || pkg || sub) return 0; // Create .bdep/. diff --git a/bdep/utility.cxx b/bdep/utility.cxx index 8caedc6..a04507a 100644 --- a/bdep/utility.cxx +++ b/bdep/utility.cxx @@ -138,6 +138,22 @@ namespace bdep } void + mk_p (const dir_path& d) + { + if (verb >= 3) + text << "mkdir -p " << d; + + try + { + try_mkdir_p (d); + } + catch (const system_error& e) + { + fail << "unable to create directory " << d << ": " << e; + } + } + + void rm (const path& f, uint16_t v) { if (verb >= v) diff --git a/tests/new.testscript b/tests/new.testscript index ca33056..8e8fd75 100644 --- a/tests/new.testscript +++ b/tests/new.testscript @@ -92,6 +92,18 @@ status += -d prj EOE } + : lib-no-version + : + { + $* -t lib,unit-tests,no-version -l c++ libfoo 2>>/"EOE" &libfoo/***; + created new library project libfoo in $~/libfoo/ + EOE + + $build libfoo/ $cxx 2>>~%EOE% + %(c\+\+|ar|ld) .+%{10} + EOE + } + : lib-binless : { @@ -220,6 +232,68 @@ status += -d prj EOE } } + + : sub + : + { + : exe + : + : Test adding a library source subdirectory to an executable project. + : + { + $* -t exe prj 2>>/"EOE" &prj/***; + created new executable project prj in $~/prj/ + EOE + + $* --subdirectory -t lib libprj -d prj 2>>/"EOE"; + created new library source subdirectory libprj in $~/prj/libprj/ + EOE + + $build prj/ $cxx 2>>~%EOE% + %(c\+\+|ar|ld) .+%{6} + EOE + } + + : bare + : + : Test filling a bare project with source subdirectories. + : + { + $* -t bare prj 2>>/"EOE" &prj/***; + created new bare project prj in $~/prj/ + EOE + + $* --subdirectory -t lib libprj -d prj 2>>/"EOE"; + created new library source subdirectory libprj in $~/prj/libprj/ + EOE + + $* --subdirectory -t exe prj -d prj 2>>/"EOE"; + created new executable source subdirectory prj in $~/prj/prj/ + EOE + + $build prj/ $cxx 2>>~%EOE% + %(c\+\+|ar|ld) .+%{6} + EOE + } + + : nested + : + : Test adding a source subdirectories to a subdirectory. + : + { + $* -t bare prj 2>>/"EOE" &prj/***; + created new bare project prj in $~/prj/ + EOE + + $* --subdirectory -t lib,unit-tests prj -d prj -o prj/core/prj 2>>/"EOE"; + created new library source subdirectory prj in $~/prj/core/prj/ + EOE + + $build prj/ $cxx 2>>~%EOE% + %(c\+\+|ar|ld) .+%{8} + EOE + } + } } : cfg |