aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-06-12 11:56:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-06-12 11:56:18 +0200
commit08f36d41ea69ca331715ac8d70b0bf8fd849f401 (patch)
treeb377f5459fdcdcbf9e8980394386b1305b7dd516
parente50b11ceb81089fc32eac7614b66daef7119f620 (diff)
Add built-in support for Windows module definition files (.def)
-rw-r--r--build2/bin/init.cxx6
-rw-r--r--build2/bin/target.cxx17
-rw-r--r--build2/bin/target.hxx12
-rw-r--r--build2/cc/link-rule.cxx52
4 files changed, 82 insertions, 5 deletions
diff --git a/build2/bin/init.cxx b/build2/bin/init.cxx
index 0761bb6..13e3289 100644
--- a/build2/bin/init.cxx
+++ b/build2/bin/init.cxx
@@ -399,6 +399,12 @@ namespace build2
t.insert<liba> ();
t.insert<libs> ();
+ // Register the def{} target type. Note that we do it here since it is
+ // input and can be specified unconditionally (i.e., not only when
+ // building for Windows).
+ //
+ t.insert<def> ();
+
// Note: libu*{} are not installable.
//
if (install_loaded)
diff --git a/build2/bin/target.cxx b/build2/bin/target.cxx
index aee2d25..a33875c 100644
--- a/build2/bin/target.cxx
+++ b/build2/bin/target.cxx
@@ -364,5 +364,22 @@ namespace build2
&file_search,
false
};
+
+ // def
+ //
+ extern const char def_ext[] = "def"; // VC14 rejects constexpr.
+
+ const target_type def::static_type
+ {
+ "def",
+ &file::static_type,
+ &target_factory<def>,
+ &target_extension_fix<def_ext>,
+ nullptr, /* default_extension */
+ &target_pattern_fix<def_ext>,
+ nullptr,
+ &file_search,
+ false
+ };
}
}
diff --git a/build2/bin/target.hxx b/build2/bin/target.hxx
index 32ef0fb..f0b427f 100644
--- a/build2/bin/target.hxx
+++ b/build2/bin/target.hxx
@@ -264,6 +264,18 @@ namespace build2
static const target_type static_type;
virtual const target_type& dynamic_type () const {return static_type;}
};
+
+ // Windows module definition (.def).
+ //
+ class def: public file
+ {
+ public:
+ using file::file;
+
+ public:
+ static const target_type static_type;
+ virtual const target_type& dynamic_type () const {return static_type;}
+ };
}
}
diff --git a/build2/cc/link-rule.cxx b/build2/cc/link-rule.cxx
index ce1a9f6..e3516ac 100644
--- a/build2/cc/link-rule.cxx
+++ b/build2/cc/link-rule.cxx
@@ -679,6 +679,14 @@ namespace build2
if (p.is_a<obj> ()) pt = &search (t, tt.obj, p.key ());
else if (p.is_a<bmi> ()) pt = &search (t, tt.bmi, p.key ());
//
+ // Windows module definition (.def). For other platforms (and for
+ // static libraries) treat it as an ordinary prerequisite.
+ //
+ else if (p.is_a<def> () && tclass == "windows" && ot != otype::a)
+ {
+ pt = &p.search (t);
+ }
+ //
// Something else. This could be something unrelated that the user
// tacked on (e.g., a doc{}). Or it could be some ad hoc input to
// the linker (say a linker script or some such).
@@ -691,6 +699,9 @@ namespace build2
// for update. This allows operations like test and install to
// skip such tacked on stuff.
//
+ // @@ This is broken since, for example, update for install will
+ // ignore ad hoc inputs.
+ //
if (current_outer_oif != nullptr)
continue;
}
@@ -1624,11 +1635,12 @@ namespace build2
// Finally, hash and compare the list of input files.
//
- // Should we capture actual files or their checksum? The only good
- // reason for capturing actual files is diagnostics: we will be able
- // to pinpoint exactly what is causing the update. On the other hand,
- // the checksum is faster and simpler. And we like simple.
+ // Should we capture actual file names or their checksum? The only good
+ // reason for capturing actual files is diagnostics: we will be able to
+ // pinpoint exactly what is causing the update. On the other hand, the
+ // checksum is faster and simpler. And we like simple.
//
+ const file* def (nullptr); // Cache if present.
{
sha256 cs;
@@ -1673,6 +1685,21 @@ namespace build2
else
hash_path (cs, f->path (), rs.out_path ());
}
+ else if ((f = pt->is_a<bin::def> ()))
+ {
+ if (tclass == "windows" && !lt.static_library ())
+ {
+ // At least link.exe only allows a single .def file.
+ //
+ if (def != nullptr)
+ fail << "multiple module definition files specified for " << t;
+
+ hash_path (cs, f->path (), rs.out_path ());
+ def = f;
+ }
+ else
+ f = nullptr; // Not an input.
+ }
else
f = pt->is_a<exe> (); // Consider executable mtime (e.g., linker).
@@ -1736,7 +1763,7 @@ namespace build2
// Ok, so we are updating. Finish building the command line.
//
- string out, out1, out2, out3; // Storage.
+ string in, out, out1, out2, out3; // Storage.
// Translate paths to relative (to working directory) ones. This results
// in easier to read diagnostics.
@@ -1841,6 +1868,12 @@ namespace build2
args.push_back (out3.c_str ());
}
+ if (def != nullptr)
+ {
+ in = "/DEF:" + relative (def->path ()).string ();
+ args.push_back (in.c_str ());
+ }
+
if (ot == otype::s)
{
// On Windows libs{} is the DLL and its first ad hoc group member
@@ -1907,6 +1940,15 @@ namespace build2
args.push_back ("-o");
args.push_back (relt.string ().c_str ());
+
+ // For MinGW the .def file is just another input.
+ //
+ if (def != nullptr)
+ {
+ in = relative (def->path ()).string ();
+ args.push_back (in.c_str ());
+ }
+
break;
}
case compiler_class::msvc: assert (false);