aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-12-19 10:42:17 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-12-19 10:42:17 +0200
commit810b7cc853836ebcba42ee0ea863a514020e1514 (patch)
treeb2540e759a2f68d6b6bf372bdefdd644c17f0b8e
parenta2ff69d049015fb8fff459561ef7ee3cd5a94952 (diff)
Add support for make dependency generation
-rw-r--r--NEWS6
-rw-r--r--xsd/cxx/options.cli53
-rw-r--r--xsd/cxx/tree/generator.cxx94
3 files changed, 152 insertions, 1 deletions
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
+ {
+ "<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"
+ {
+ "<suffix>",
+ "Use the provided <suffix> instead of the default \cb{.d} to
+ construct the name of the dependency file."
+ };
+
+ NarrowString --dep-regex
+ {
+ "<regex>",
+ "Use the provided expression to construct the name of the dependency
+ file. <regex> 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 <cutl/compiler/sloc-counter.hxx>
#include <xsd-frontend/semantic-graph.hxx>
+#include <xsd-frontend/generators/dependencies.hxx>
#include <cxx/tree/generator.hxx>
@@ -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)