From 810b7cc853836ebcba42ee0ea863a514020e1514 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 19 Dec 2012 10:42:17 +0200 Subject: Add support for make dependency generation --- NEWS | 6 +++ xsd/cxx/options.cli | 53 ++++++++++++++++++++++++++ xsd/cxx/tree/generator.cxx | 94 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 2957a53..2a3cd76 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,12 @@ C++/Tree the copy assignment operators for such types are declared private and left unimplemented. + * New option, --generate-dep, triggers the generation of the make + dependency file (.d) for the generated C++ files. Other options + controlling dependency generation are: --dep-phony, --dep-target, + --dep-suffix, and --dep-regex. For details, refer to the XSD + compiler command line manual (man pages). + * Binary representation now stores string-based enumerations as integer values corresponding to C++ enumerators instead of string literals. diff --git a/xsd/cxx/options.cli b/xsd/cxx/options.cli index 4f8aeb9..b80f71f 100644 --- a/xsd/cxx/options.cli +++ b/xsd/cxx/options.cli @@ -463,5 +463,58 @@ namespace CXX you would like to use the same generated code across multiple platforms." }; + + // Make dependency generation. + // + bool --generate-dep + { + "Generate \cb{make} dependency information. This option triggers the + creation of the \cb{.d} file containing the dependencies of the + generated files on the main schema file as well as all the schema + files that it includes/imports, transitively. This dependency file + is then normally included into the main \cb{makefile} to implement + automatic dependency tracking. + + Note also that automatic dependency generation is not supported in + the file-per-type mode (\cb{--file-per-type}). In this case, all + the generated files are produced with a single compiler invocation + and depend on all the schemas. As a result, it is easier to establish + such a dependency manually, perhaps with the help of the + \cb{--file-list*} options." + }; + + bool --dep-phony + { + "Generate phony targets for included/imported schema files, causing + each to depend on nothing. Such dummy rules work around \cb{make} + errors caused by the removal of schema files without also updating + the dependency file to match." + }; + + NarrowStrings --dep-target + { + "", + "Change the target of the dependency rule. By default it contains + all the generated C++ files as well as the dependency file itself, + without any directory prefixes. If you require multiple targets, + then you can specify them as a single, space-separated argument or + you can repeat this option multiple times." + }; + + NarrowString --dep-suffix = ".d" + { + "", + "Use the provided instead of the default \cb{.d} to + construct the name of the dependency file." + }; + + NarrowString --dep-regex + { + "", + "Use the provided expression to construct the name of the dependency + file. is a Perl-like regular expression in the form + \c{\b{/}\i{pattern}\b{/}\i{replacement}\b{/}}. See also the REGEX + AND SHELL QUOTING section below." + }; }; } diff --git a/xsd/cxx/tree/generator.cxx b/xsd/cxx/tree/generator.cxx index ff2b705..d60e5bc 100644 --- a/xsd/cxx/tree/generator.cxx +++ b/xsd/cxx/tree/generator.cxx @@ -16,6 +16,7 @@ #include #include +#include #include @@ -290,6 +291,14 @@ namespace CXX bool inline_ (ops.generate_inline () && !generate_xml_schema); bool forward (ops.generate_forward () && !generate_xml_schema); bool source (!generate_xml_schema); + bool gen_dep (ops.generate_dep () && source); + + if (gen_dep && fpt) + { + wcerr << "error: dependency generation not support in " << + "file-per-type mode" << endl; + throw Failed (); + } // Generate code. // @@ -299,6 +308,7 @@ namespace CXX NarrowString ixx_suffix (ops.ixx_suffix ()); NarrowString cxx_suffix (ops.cxx_suffix ()); NarrowString fwd_suffix (ops.fwd_suffix ()); + NarrowString dep_suffix (ops.dep_suffix ()); Regex hxx_expr (ops.hxx_regex ().empty () ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + hxx_suffix + "#" @@ -316,6 +326,10 @@ namespace CXX ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + fwd_suffix + "#" : ops.fwd_regex ()); + Regex dep_expr (ops.dep_regex ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + dep_suffix + "#" + : ops.dep_regex ()); + if (!hxx_expr.match (name)) { wcerr << "error: header expression '" << @@ -348,13 +362,23 @@ namespace CXX throw Failed (); } + if (gen_dep && !dep_expr.match (name)) + { + wcerr << "error: dependency expression '" << + dep_expr.regex ().str ().c_str () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + NarrowString hxx_name (hxx_expr.replace (name)); NarrowString ixx_name (inline_ ? ixx_expr.replace (name) : NarrowString ()); NarrowString fwd_name (forward ? fwd_expr.replace (name) : NarrowString ()); + NarrowString dep_name (gen_dep ? dep_expr.replace (name) : NarrowString ()); Path hxx_path (hxx_name, boost::filesystem::native); Path ixx_path (ixx_name, boost::filesystem::native); Path fwd_path (fwd_name, boost::filesystem::native); + Path dep_path (dep_name, boost::filesystem::native); Paths cxx_paths; if (source) @@ -420,6 +444,7 @@ namespace CXX hxx_path = out_dir / hxx_path; ixx_path = out_dir / ixx_path; fwd_path = out_dir / fwd_path; + dep_path = out_dir / dep_path; for (Paths::iterator i (cxx_paths.begin ()); i != cxx_paths.end (); ++i) @@ -431,8 +456,24 @@ namespace CXX WideOutputFileStream hxx (hxx_path, ios_base::out); WideOutputFileStream ixx; WideOutputFileStream fwd; + WideOutputFileStream dep; WideOutputFileStreams cxx; + // DEP + // + if (gen_dep) + { + dep.open (dep_path, ios_base::out); + + if (!dep.is_open ()) + { + wcerr << dep_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (dep_path); + file_list.push_back (dep_path.native_file_string ()); + } // FWD // @@ -450,7 +491,6 @@ namespace CXX file_list.push_back (fwd_path.native_file_string ()); } - // HXX // if (!hxx.is_open ()) @@ -580,6 +620,58 @@ namespace CXX if (guard_prefix) guard_prefix += '_'; + // DEP + // + if (gen_dep) + { + NarrowString target; + NarrowStrings const& ts (ops.dep_target ()); + + if (!ts.empty ()) + { + for (NarrowStrings::const_iterator i (ts.begin ()); + i != ts.end (); ++i) + target += (target.empty () ? "" : " \\\n") + *i; + } + else + { + target = hxx_path.leaf (); + + if (forward) + target += " \\\n" + fwd_path.leaf (); + + if (inline_) + target += " \\\n" + ixx_path.leaf (); + + for (Paths::iterator i (cxx_paths.begin ()); + i != cxx_paths.end (); ++i) + target += " \\\n" + i->leaf (); + + target += " \\\n" + dep_path.leaf (); + } + + dep << target.c_str () << ':'; + + XSDFrontend::Generators::Dependencies gen; + Paths prq (gen.generate (schema, file_path)); + + for (Paths::iterator i (prq.begin ()); i != prq.end (); ++i) + dep << " \\" << endl + << " " << i->string (); + + dep << endl; + + // If requested, generate phony rules for included/imported schemas + // but not the main file which is the first in the list. + // + if (ops.dep_phony () && prq.size () > 1) + { + for (Paths::iterator i (prq.begin () + 1); i != prq.end (); ++i) + dep << endl + << i->string () << ':' << endl; + } + } + // FWD // if (forward) -- cgit v1.1