From 1adbf7b710d52958f6c0168ccb492252c1f19d4a Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 13 Mar 2020 08:48:43 +0200 Subject: Cleanup and make config/utility.?xx part of build system core --- libbuild2/buildfile | 4 +- libbuild2/cc/compile-rule.cxx | 6 +- libbuild2/config/init.cxx | 3 +- libbuild2/config/module.cxx | 16 ++++ libbuild2/config/module.hxx | 26 ++++-- libbuild2/config/operation.cxx | 4 +- libbuild2/config/utility.cxx | 180 ++--------------------------------------- libbuild2/config/utility.hxx | 106 +++++++++++++++--------- libbuild2/config/utility.txx | 3 - libbuild2/context.cxx | 10 +-- libbuild2/context.hxx | 12 --- libbuild2/file.cxx | 162 +++++++++++++++++++++++++++++++++++-- libbuild2/file.hxx | 14 ++++ 13 files changed, 289 insertions(+), 257 deletions(-) diff --git a/libbuild2/buildfile b/libbuild2/buildfile index 63078ea..a253ab1 100644 --- a/libbuild2/buildfile +++ b/libbuild2/buildfile @@ -34,7 +34,9 @@ lib{build2}: cxx{utility-uninstalled}: for_install = false # These are "core modules" that come bundled with libbuild2 (see also unit # tests loop below). Note that the build system core can still function -# without them or with their alternative implementations. +# without them or with their alternative implementations. Also note that +# config/utility.?xx are part of the build system core (see comments in the +# header for details). # # NOTE: remember to update import_modules() in libbuild2/modules.cxx if adding # a new such module. diff --git a/libbuild2/cc/compile-rule.cxx b/libbuild2/cc/compile-rule.cxx index a5c4cfb..1cefcc5 100644 --- a/libbuild2/cc/compile-rule.cxx +++ b/libbuild2/cc/compile-rule.cxx @@ -15,8 +15,6 @@ #include // mtime() #include -#include // create_project() - #include #include @@ -5316,14 +5314,14 @@ namespace build2 extra += string (x) + ".features.modules = true"; - config::create_project ( + create_project ( pd, as->out_path ().relative (pd), /* amalgamation */ {}, /* boot_modules */ extra, /* root_pre */ {string (x) + '.'}, /* root_modules */ "", /* root_post */ - false, /* config */ + nullopt, /* config */ false, /* buildfile */ "the cc module", 2); /* verbosity */ diff --git a/libbuild2/config/init.cxx b/libbuild2/config/init.cxx index 8dd4d8b..ca34d52 100644 --- a/libbuild2/config/init.cxx +++ b/libbuild2/config/init.cxx @@ -300,7 +300,8 @@ namespace build2 { // Initialize the config entry points in the build system core. // - config_save_variable = &save_variable; + config_save_variable = &module::save_variable; + config_save_module = &module::save_module; config_preprocess_create = &preprocess_create; return mod_functions; diff --git a/libbuild2/config/module.cxx b/libbuild2/config/module.cxx index 176eef0..96107cc 100644 --- a/libbuild2/config/module.cxx +++ b/libbuild2/config/module.cxx @@ -3,6 +3,8 @@ #include +#include + using namespace std; namespace build2 @@ -45,12 +47,26 @@ namespace build2 return true; } + void module:: + save_variable (scope& rs, const variable& var, uint64_t flags) + { + if (module* m = rs.find_module (module::name)) + m->save_variable (var, flags); + } + bool module:: save_module (const char* name, int prio) { return saved_modules.insert (string ("config.") += name, prio).second; } + void module:: + save_module (scope& rs, const char* name, int prio) + { + if (module* m = rs.find_module (module::name)) + m->save_module (name, prio); + } + const string module::name ("config"); const uint64_t module::version (1); } diff --git a/libbuild2/config/module.hxx b/libbuild2/config/module.hxx index 28c73a3..ade75cd 100644 --- a/libbuild2/config/module.hxx +++ b/libbuild2/config/module.hxx @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -51,14 +52,6 @@ namespace build2 // Priority order with INT32_MIN being the highest. Modules with the // same priority are saved in the order inserted. // - // Generally, the idea is that we want higher-level modules at the top - // of the file since that's the configuration that we usualy want to - // change. So we have the following priority bands/defaults: - // - // 101-200/150 - code generators (e.g., yacc, bison) - // 201-300/250 - compilers (e.g., C, C++), - // 301-400/350 - binutils (ar, ld) - // std::multimap order; pair @@ -82,9 +75,15 @@ namespace build2 bool save_variable (const variable&, uint64_t flags = 0); + static void + save_variable (scope&, const variable&, uint64_t); + bool save_module (const char* name, int prio = 0); + static void + save_module (scope&, const char*, int); + // Return true if the variable is already saved. // bool @@ -102,6 +101,17 @@ namespace build2 static const string name; static const uint64_t version; }; + + // Implementation-specific utilities. + // + + inline path + config_file (const scope& rs) + { + return (rs.out_path () / + rs.root_extra->build_dir / + "config." + rs.root_extra->build_ext); + } } } diff --git a/libbuild2/config/operation.cxx b/libbuild2/config/operation.cxx index 2138986..07110e0 100644 --- a/libbuild2/config/operation.cxx +++ b/libbuild2/config/operation.cxx @@ -13,7 +13,7 @@ #include #include -#include +#include // save_* using namespace std; using namespace butl; @@ -1224,7 +1224,7 @@ namespace build2 "", /* root_pre */ rmod, "", /* root_post */ - true, /* config */ + "config", /* config */ true, /* buildfile */ "the create meta-operation"); diff --git a/libbuild2/config/utility.cxx b/libbuild2/config/utility.cxx index a39d3e0..b9fc513 100644 --- a/libbuild2/config/utility.cxx +++ b/libbuild2/config/utility.cxx @@ -3,17 +3,17 @@ #include -#include -#include -#include -#include - -#include - using namespace std; namespace build2 { + void (*config_save_variable) (scope&, const variable&, uint64_t); + void (*config_save_module) (scope&, const char*, int); + const string& (*config_preprocess_create) (context&, + values&, + vector_view&, + bool, + const location&); namespace config { pair @@ -126,171 +126,5 @@ namespace build2 else return false; } - - void - save_variable (scope& rs, const variable& var, uint64_t flags) - { - if (module* m = rs.find_module (module::name)) - m->save_variable (var, flags); - } - - void - save_module (scope& rs, const char* name, int prio) - { - if (module* m = rs.find_module (module::name)) - m->save_module (name, prio); - } - - void - create_project (const dir_path& d, - const build2::optional& amal, - const strings& bmod, - const string& rpre, - const strings& rmod, - const string& rpos, - bool config, - bool buildfile, - const char* who, - uint16_t verbosity) - { - string hdr ("# Generated by " + string (who) + ". Edit if you know" - " what you are doing.\n" - "#"); - - // If the directory exists, verify it's empty. Otherwise, create it. - // - if (exists (d)) - { - if (!empty (d)) - fail << "directory " << d << " exists and is not empty"; - } - else - mkdir_p (d, verbosity); - - // Create the build/ subdirectory. - // - // Note that for now we use the standard build file/directory scheme. - // - mkdir (d / std_build_dir, verbosity); - - // Write build/bootstrap.build. - // - { - path f (d / std_bootstrap_file); - - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; - - try - { - ofdstream ofs (f); - - ofs << hdr << endl - << "project =" << endl; - - if (amal) - { - ofs << "amalgamation ="; - - if (!amal->empty ()) - { - ofs << ' '; - to_stream (ofs, *amal, true /* representation */); - } - - ofs << endl; - } - - ofs << endl; - - if (config) - ofs << "using config" << endl; - - for (const string& m: bmod) - { - if (!config || m != "config") - ofs << "using " << m << endl; - } - - ofs.close (); - } - catch (const io_error& e) - { - fail << "unable to write to " << f << ": " << e; - } - } - - // Write build/root.build. - // - { - path f (d / std_root_file); - - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; - - try - { - ofdstream ofs (f); - - ofs << hdr << endl; - - if (!rpre.empty ()) - ofs << rpre << endl - << endl; - - for (const string& cm: rmod) - { - // If the module name start with '?', then use optional load. - // - bool opt (cm.front () == '?'); - string m (cm, opt ? 1 : 0); - - // Append .config unless the module name ends with '.', in which - // case strip it. - // - if (m.back () == '.') - m.pop_back (); - else - m += ".config"; - - ofs << "using" << (opt ? "?" : "") << " " << m << endl; - } - - if (!rpos.empty ()) - ofs << endl - << rpre << endl; - - ofs.close (); - } - catch (const io_error& e) - { - fail << "unable to write to " << f << ": " << e; - } - } - - // Write root buildfile. - // - if (buildfile) - { - path f (d / std_buildfile_file); - - if (verb >= verbosity) - text << (verb >= 2 ? "cat >" : "save ") << f; - - try - { - ofdstream ofs (f); - - ofs << hdr << endl - << "./: {*/ -build/}" << endl; - - ofs.close (); - } - catch (const io_error& e) - { - fail << "unable to write to " << f << ": " << e; - } - } - } } } diff --git a/libbuild2/config/utility.hxx b/libbuild2/config/utility.hxx index 3e01cd1..493d296 100644 --- a/libbuild2/config/utility.hxx +++ b/libbuild2/config/utility.hxx @@ -10,14 +10,73 @@ #include #include -#include #include namespace build2 { + // Note that the utility functions in this file are part of the build system + // core rather than the config module. They define the basic configuration + // semantics that should be applicable to both transient configurations as + // well as to other implementations of configuration persistence. + // + // The only persistence-specific aspects of this functionality are marking + // of the variables as to be persisted (saved, potentially with flags), + // establishing the module saving order (priority), and configuration + // creation (the create meta-operation implementation) These are accessed + // through the config module entry points (which are NULL for transient + // configurations). Note also that the exact interpretation of the save + // flags and module order depends on the config module implementation (which + // may ignore them as not applicable). An implementation may also define + // custom save flags (for example, accessible through the config.save + // attribute). Such flags should start from 0x100000000. + // + LIBBUILD2_SYMEXPORT extern void + (*config_save_variable) (scope&, const variable&, uint64_t); + + LIBBUILD2_SYMEXPORT extern void + (*config_save_module) (scope&, const char*, int); + + LIBBUILD2_SYMEXPORT extern const string& + (*config_preprocess_create) (context&, + values&, + vector_view&, + bool, + const location&); + namespace config { + // Mark the variable to be saved during configuration. + // + const uint64_t save_default_commented = 0x01; // Based on value::extra. + const uint64_t save_null_omitted = 0x02; // Treat NULL as undefined. + + inline void + save_variable (scope& rs, const variable& var, uint64_t flags = 0) + { + if (config_save_variable != nullptr) + config_save_variable (rs, var, flags); + } + + // Establish module save order/priority with INT32_MIN being the highest. + // Modules with the same priority are saved in the order inserted. + // + // Generally, for user-editable persisten configuration, we want higher- + // level modules at the top of the file since that's the configuration + // that the user usually wants to change. As a result, we define the + // following priority bands/defaults: + // + // 101-200/150 - code generators (e.g., yacc, bison) + // 201-300/250 - compilers (e.g., C, C++), + // 301-400/350 - binutils (ar, ld) + // + inline void + save_module (scope& rs, const char* module, int prio = 0) + { + if (config_save_module != nullptr) + config_save_module (rs, module, prio); + } + // Set, if necessary, a required config.* variable. // // If override is true and the variable doesn't come from this root scope @@ -33,9 +92,12 @@ namespace build2 // (always defined) to pass along its location (could be used to detect // inheritance, etc). // - // Note also that if save_flags has save_commented, then a default value - // is never considered "new" since for such variables absence of a value - // means the default value. + // Note also that if save_flags has save_default_commented, then a default + // value is never considered "new" since for such variables absence of a + // value means the default value. + // + // @@ Should save_null_omitted be interpreted to treat null as undefined? + // Sounds logical. // template pair @@ -139,42 +201,6 @@ namespace build2 // LIBBUILD2_SYMEXPORT bool unconfigured (scope& rs, const string& var, bool value); - - // Enter the variable so that it is saved during configuration. See - // config::module for details. - // - const uint64_t save_default_commented = 0x01; // Based on value::extra. - const uint64_t save_null_omitted = 0x02; // Treat NULL as undefined. - - LIBBUILD2_SYMEXPORT void - save_variable (scope& rs, const variable&, uint64_t flags = 0); - - // Establish module order/priority. See config::module for details. - // - LIBBUILD2_SYMEXPORT void - save_module (scope& rs, const char* module, int prio = 0); - - // Create a project in the specified directory. - // - LIBBUILD2_SYMEXPORT void - create_project (const dir_path& d, - const build2::optional& amalgamation, - const strings& boot_modules, // Bootstrap modules. - const string& root_pre, // Extra root.build text. - const strings& root_modules, // Root modules. - const string& root_post, // Extra root.build text. - bool config, // Load config module. - bool buildfile, // Create root buildfile. - const char* who, // Who is creating it. - uint16_t verbosity = 1); // Diagnostic verbosity. - - inline path - config_file (const scope& rs) - { - return (rs.out_path () / - rs.root_extra->build_dir / - "config." + rs.root_extra->build_ext); - } } } diff --git a/libbuild2/config/utility.txx b/libbuild2/config/utility.txx index 670a701..f52df8d 100644 --- a/libbuild2/config/utility.txx +++ b/libbuild2/config/utility.txx @@ -1,9 +1,6 @@ // file : libbuild2/config/utility.txx -*- C++ -*- // license : MIT; see accompanying LICENSE file -#include -#include // current_mif - namespace build2 { namespace config diff --git a/libbuild2/context.cxx b/libbuild2/context.cxx index 4082e0c..827894b 100644 --- a/libbuild2/context.cxx +++ b/libbuild2/context.cxx @@ -21,6 +21,8 @@ #include #include +#include // config_preprocess_create + using namespace std; using namespace butl; @@ -892,12 +894,4 @@ namespace build2 //text << this_thread::get_id () << " phase restore " << n << " " << o; } - - void (*config_save_variable) (scope&, const variable&, uint64_t); - - const string& (*config_preprocess_create) (context&, - values&, - vector_view&, - bool, - const location&); } diff --git a/libbuild2/context.hxx b/libbuild2/context.hxx index a2bfe3d..ea2c017 100644 --- a/libbuild2/context.hxx +++ b/libbuild2/context.hxx @@ -589,18 +589,6 @@ namespace build2 atomic_count* task_count; bool phase; }; - - // Config module entry points. - // - LIBBUILD2_SYMEXPORT extern void (*config_save_variable) ( - scope&, const variable&, uint64_t flags); - - LIBBUILD2_SYMEXPORT extern const string& (*config_preprocess_create) ( - context&, - values&, - vector_view&, - bool lifted, - const location&); } #include diff --git a/libbuild2/file.cxx b/libbuild2/file.cxx index 225c506..7903918 100644 --- a/libbuild2/file.cxx +++ b/libbuild2/file.cxx @@ -6,7 +6,7 @@ #include #include #include -#include // exists() +#include #include #include @@ -14,6 +14,8 @@ #include #include +#include // save_variable() + using namespace std; using namespace butl; @@ -1369,8 +1371,7 @@ namespace build2 // Mark as part of config. // - if (config_save_variable != nullptr) - config_save_variable (iroot, var, 0 /* flags */); + config::save_variable (iroot, var); // Empty config.import.* value means don't look in subprojects or // amalgamations and go straight to the rule-specific import (e.g., @@ -1405,8 +1406,7 @@ namespace build2 if (r.empty ()) fail (loc) << "empty path in " << var.name; - if (config_save_variable != nullptr) - config_save_variable (iroot, var, 0 /* flags */); + config::save_variable (iroot, var); } return r; @@ -1786,4 +1786,156 @@ namespace build2 dr << endf; } + + void + create_project (const dir_path& d, + const optional& amal, + const strings& bmod, + const string& rpre, + const strings& rmod, + const string& rpos, + const optional& config, + bool buildfile, + const char* who, + uint16_t verbosity) + { + string hdr ("# Generated by " + string (who) + ". Edit if you know" + " what you are doing.\n" + "#"); + + // If the directory exists, verify it's empty. Otherwise, create it. + // + if (exists (d)) + { + if (!empty (d)) + fail << "directory " << d << " exists and is not empty"; + } + else + mkdir_p (d, verbosity); + + // Create the build/ subdirectory. + // + // Note that for now we use the standard build file/directory scheme. + // + mkdir (d / std_build_dir, verbosity); + + // Write build/bootstrap.build. + // + { + path f (d / std_bootstrap_file); + + if (verb >= verbosity) + text << (verb >= 2 ? "cat >" : "save ") << f; + + try + { + ofdstream ofs (f); + + ofs << hdr << endl + << "project =" << endl; + + if (amal) + { + ofs << "amalgamation ="; + + if (!amal->empty ()) + { + ofs << ' '; + to_stream (ofs, *amal, true /* representation */); + } + + ofs << endl; + } + + ofs << endl; + + if (config) + ofs << "using " << *config << endl; + + for (const string& m: bmod) + { + if (!config || m != *config) + ofs << "using " << m << endl; + } + + ofs.close (); + } + catch (const io_error& e) + { + fail << "unable to write to " << f << ": " << e; + } + } + + // Write build/root.build. + // + { + path f (d / std_root_file); + + if (verb >= verbosity) + text << (verb >= 2 ? "cat >" : "save ") << f; + + try + { + ofdstream ofs (f); + + ofs << hdr << endl; + + if (!rpre.empty ()) + ofs << rpre << endl + << endl; + + for (const string& cm: rmod) + { + // If the module name start with '?', then use optional load. + // + bool opt (cm.front () == '?'); + string m (cm, opt ? 1 : 0); + + // Append .config unless the module name ends with '.', in which + // case strip it. + // + if (m.back () == '.') + m.pop_back (); + else + m += ".config"; + + ofs << "using" << (opt ? "?" : "") << " " << m << endl; + } + + if (!rpos.empty ()) + ofs << endl + << rpre << endl; + + ofs.close (); + } + catch (const io_error& e) + { + fail << "unable to write to " << f << ": " << e; + } + } + + // Write root buildfile. + // + if (buildfile) + { + path f (d / std_buildfile_file); + + if (verb >= verbosity) + text << (verb >= 2 ? "cat >" : "save ") << f; + + try + { + ofdstream ofs (f); + + ofs << hdr << endl + << "./: {*/ -build/}" << endl; + + ofs.close (); + } + catch (const io_error& e) + { + fail << "unable to write to " << f << ": " << e; + } + } + } } diff --git a/libbuild2/file.hxx b/libbuild2/file.hxx index 2e7eddd..d3c6787 100644 --- a/libbuild2/file.hxx +++ b/libbuild2/file.hxx @@ -261,6 +261,20 @@ namespace build2 // const target* import_existing (context&, const prerequisite_key&); + + // Create a build system project in the specified directory. + // + LIBBUILD2_SYMEXPORT void + create_project (const dir_path&, + const optional& amalgamation, + const strings& boot_modules, // Bootstrap modules. + const string& root_pre, // Extra root.build text. + const strings& root_modules, // Root modules. + const string& root_post, // Extra root.build text. + const optional& config, // Config module to load. + bool buildfile, // Create root buildfile. + const char* who, // Who is creating it. + uint16_t verbosity = 1); // Diagnostic verbosity. } #include -- cgit v1.1