From 08f36d41ea69ca331715ac8d70b0bf8fd849f401 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 12 Jun 2018 11:56:18 +0200 Subject: Add built-in support for Windows module definition files (.def) --- build2/bin/init.cxx | 6 ++++++ build2/bin/target.cxx | 17 ++++++++++++++++ build2/bin/target.hxx | 12 ++++++++++++ build2/cc/link-rule.cxx | 52 ++++++++++++++++++++++++++++++++++++++++++++----- 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 (); t.insert (); + // 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 (); + // 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, + &target_extension_fix, + nullptr, /* default_extension */ + &target_pattern_fix, + 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 ()) pt = &search (t, tt.obj, p.key ()); else if (p.is_a ()) 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 () && 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 ())) + { + 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 (); // 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); -- cgit v1.1