Skip to content

Commit a72f5b9

Browse files
authored
LinkerInvocation: refactor argument forwarding approach (#11)
General workflow for generating an "rpath'd" import library: * Run the linker (link.exe) and allow it to produce a dll and import library. * Parse the linker command line, and extract what we think we need. Pass that to the librarian (lib) along with the absolute path to the dll as the name. * Replace the old import lib with the new one. Previously the wrapper had an ad-hoc approach to forwarding arguments from the linker to the librarian; this resulted in cases where CLI args needed by the librarian would be dropped. This PR dds a map including every argument that is valid for both the linker and librarian (and makes sense to forward for our case), and checks that map against the linker CLI to ensure we're forwarding all arguments verbatim (with handling for quoting).
1 parent 38518db commit a72f5b9

File tree

3 files changed

+38
-16
lines changed

3 files changed

+38
-16
lines changed

src/ld.cxx

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,18 @@ DWORD LdInvocation::InvokeToolchain() {
3636
std::string const imp_lib_name = link_run.get_implib_name();
3737
std::string dll_name = link_run.get_mangled_out();
3838
std::string const abs_out_imp_lib_name = imp_lib_name + ".dll-abs.lib";
39-
std::string const def_file = link_run.get_def_file();
40-
std::string def_line = "-def";
41-
def_line += !def_file.empty() ? ":" + def_file : "";
39+
std::string def = "-def ";
40+
std::string piped_args = link_run.get_lib_link_args();
4241
// create command line to generate new import lib
43-
this->rpath_executor = ExecuteCommand(
44-
"lib.exe",
45-
LdInvocation::ComposeCommandLists({
46-
{def_line, "-name:" + dll_name, "-out:" + abs_out_imp_lib_name},
47-
{link_run.get_rsp_file()},
48-
this->obj_args,
49-
this->lib_args,
50-
this->lib_dir_args,
51-
}));
42+
this->rpath_executor =
43+
ExecuteCommand("lib.exe", LdInvocation::ComposeCommandLists({
44+
{def, piped_args, "-name:" + dll_name,
45+
"-out:" + abs_out_imp_lib_name},
46+
{link_run.get_rsp_file()},
47+
this->obj_args,
48+
this->lib_args,
49+
this->lib_dir_args,
50+
}));
5251
this->rpath_executor.Execute();
5352
DWORD const err_code = this->rpath_executor.Join();
5453
if (err_code != 0) {

src/linker_invocation.cxx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ void LinkerInvocation::Parse() {
3232
for (auto token = this->tokens_.begin(); token != this->tokens_.end();
3333
++token) {
3434
std::string normal_token = *token;
35-
lower(normal_token);
35+
normalArg(normal_token);
3636
// implib specifies the eventuall import libraries name_
3737
// and thus will contain a ".lib" extension, which
3838
// the next check will process as a library argument
@@ -53,16 +53,16 @@ void LinkerInvocation::Parse() {
5353
this->output_ = split(*token, ":")[1];
5454
} else if (endswith(normal_token, ".obj")) {
5555
this->objs_.push_back(*token);
56-
} else if (normal_token.find("def:") != std::string::npos) {
57-
StrList def_line = split(*token, ":");
58-
this->def_file_ = def_line[1];
5956
} else if (startswith(normal_token, "@") &&
6057
endswith(normal_token, ".rsp")) {
6158
// RSP files are used to describe object files, libraries, other CLI
6259
// Switches relevant to the tool the rsp file is being passed to
6360
// Primarily utilized by CMake and MSBuild projects to bypass
6461
// Command line length limits
6562
this->rsp_file_ = *token;
63+
} else if (this->piped_args_.find(normal_token) !=
64+
this->piped_args_.end()) {
65+
this->piped_args_.at(normal_token).emplace_back(normal_token);
6666
}
6767
}
6868
std::string const ext = this->is_exe_ ? ".exe" : ".dll";
@@ -83,6 +83,22 @@ std::string LinkerInvocation::get_implib_name() {
8383
return this->implibname_;
8484
}
8585

86+
std::string LinkerInvocation::get_lib_link_args() {
87+
std::string lib_link_line;
88+
for (const auto& var_args : this->piped_args_) {
89+
// Most of these should be single arguments
90+
// however some can be defined multiple times
91+
// namely libpath and include
92+
// this allows for all arguments to be processed
93+
// correctly
94+
auto vars = var_args.second;
95+
if (!vars.empty()) {
96+
lib_link_line += join(var_args.second);
97+
}
98+
}
99+
return lib_link_line;
100+
}
101+
86102
std::string LinkerInvocation::get_def_file() {
87103
return this->def_file_;
88104
}

src/linker_invocation.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class LinkerInvocation {
2222
std::string get_implib_name();
2323
std::string get_def_file();
2424
std::string get_rsp_file();
25+
std::string get_lib_link_args();
2526

2627
private:
2728
std::string line_;
@@ -34,4 +35,10 @@ class LinkerInvocation {
3435
StrList libs_;
3536
StrList objs_;
3637
bool is_exe_;
38+
std::map<std::string, StrList> piped_args_ = {
39+
{"def", {}}, {"export", {}}, {"include", {}},
40+
{"libpath", {}}, {"ltcg", {}}, {"machine", {}},
41+
{"nodefaultlib", {}}, {"subsystem", {}}, {"verbose", {}},
42+
{"wx", {}},
43+
};
3744
};

0 commit comments

Comments
 (0)