diff --git a/changelog/noxlinker.dd b/changelog/noxlinker.dd deleted file mode 100644 index 3fdb079c05e2..000000000000 --- a/changelog/noxlinker.dd +++ /dev/null @@ -1,32 +0,0 @@ -New `-preview=noXlinker` compiler flag to address issue 6952 - -On Posix, `dmd` currently passes `-L`-prefixed compiler flags through the linker driver (e.g. `cc`) -to the linker (e.g. `ld`) by prepending them with `-Xlinker`. Therefore, it is currently -not possible to pass flags directly to the linker driver. Some flags affected by this are -`-static`, `-nostartfiles`, `-nodefaultlibs`, and `-nostdlib` to name a few. - -With this release, a new compiler flag, `-preview=noXlinker`, has been added to remedy -the issue. It will prevent the compiler from prepending `-Xlinker` to any `-L`-prefixed flags so -the user can pass flags direclty to the linker driver. Users who would like to pass `-L`-prefixed -flags through the linker driver to the linker should explicitly prepend them with `-L-Xlinker`. - -Examples: -- `dmd -L-nostartfiles` will invoke the linker driver as `cc -Xlinker -nostartfiles` which is not -correct. -- `dmd -preview=noXlinker -L-nostartfiles` will invoke the linker driver as `cc -nostartfiles` which -will achieve the desired result. -- `dmd -L-e -Lstart` will invoke the linker driver as `cc -Xlinker -e -Xlinker start`. -- `dmd -preview=noXlinker -L-Xlinker -L-e -L-Xlinker -Lstart` will invoke thee linker driver as -`cc -Xlinker -e -Xlinker start`. - -If `-preview=noXlinker` is used with the existing `dmd.conf` file, it may be necessary to prepend -`-L-Xlinker` for any existing arguments that need it. For example, if the `dmd.conf` file reads -`--export-dyamic`, and the compiler is invoked with `-preview=noXlinker`, modify the `dmd.conf` file -to read `-L-Xlinker -L--export-dynamic`. - -It is hoped that `-preview=noXlinker` will some day become the default. If and when that happens -a `-revert=noXlinker` flag can be added to revert back to the old behavior. - -See also: -- $(LINK2 https://issues.dlang.org/show_bug.cgi?id=6952, Issue 6952) -- $(LINK2 https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html, GCC Link Options) diff --git a/changelog/xcc.dd b/changelog/xcc.dd new file mode 100644 index 000000000000..db28185983c7 --- /dev/null +++ b/changelog/xcc.dd @@ -0,0 +1,19 @@ +New `-Xcc` compiler flag to address issue 6952 + +On POSIX, `dmd` passes `-L`-prefixed compiler flags through the linker driver (`cc` by default) to +the linker (e.g. `ld`) by prepending them with `-Xlinker`. Therefore, it was not possible to pass +flags directly to the linker driver. + +This release adds a new compiler flag, `-Xcc`, which specifies a flag to pass to the linker driver. +This switch has already existed in the LDC compiler for several releases. Some use cases for it +would be `-nostartfiles`, `-pthread`, and `-static`, which can now be specified as +`-Xcc=-nostartfiles`, `-Xcc=-pthread`, and `-Xcc=-static` respectively. + +Note that it was previously also possible to specify linker driver options by setting the `CC` +environment variable, e.g. `CC='cc -pthread' dmd ...`, or by setting the `CC` variable to point to a +custom linker driver wrapper script. `-Xcc` improves on this through composability and better +opportunities for integration into build systems. + +See also: +- $(LINK2 https://issues.dlang.org/show_bug.cgi?id=6952, Issue 6952) +- $(LINK2 https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html, GCC Link Options) diff --git a/src/dmd/cli.d b/src/dmd/cli.d index d16acecb0685..9bd07111ea50 100644 --- a/src/dmd/cli.d +++ b/src/dmd/cli.d @@ -418,7 +418,7 @@ dmd -cov -unittest myprog.d "pass linkerflag to link", `Pass $(I linkerflag) to the $(WINDOWS linker $(OPTLINK)) - $(UNIX linker), for example,`, + $(UNIX linker), for example, ld`, ), Option("lib", "generate library rather than object files", @@ -673,6 +673,11 @@ dmd -cov -unittest myprog.d Option("Xf=", "write JSON file to filename" ), + Option("Xcc=", + "pass driverflag to linker driver (cc)", + "Pass $(I driverflag) to the linker driver (`$CC` or `cc`)", + TargetOS.all & ~TargetOS.windows + ), ]; /// Representation of a CLI feature @@ -727,8 +732,6 @@ dmd -cov -unittest myprog.d "enable rvalue arguments to ref parameters"), Feature("nosharedaccess", "noSharedAccess", "disable access to shared memory objects"), - Feature("noXlinker", "noXlinker", - "do not prepend `-Xlinker` to `-L` command-line arguments when invoking the linker"), ]; } diff --git a/src/dmd/globals.d b/src/dmd/globals.d index 5680ce0d9fbd..7b74cc6992b0 100644 --- a/src/dmd/globals.d +++ b/src/dmd/globals.d @@ -184,8 +184,6 @@ extern (C++) struct Param bool markdown; // enable Markdown replacements in Ddoc bool vmarkdown; // list instances of Markdown replacements in Ddoc - bool noXlinker; // do not prepend `-Xlinker` to `-L` command-line options when invoking the linker - bool showGaggedErrors; // print gagged errors anyway bool printErrorContext; // print errors with the error context (the error line in the source file) bool manual; // open browser on compiler manual @@ -266,6 +264,7 @@ extern (C++) struct Param // Linker stuff Array!(const(char)*) objfiles; Array!(const(char)*) linkswitches; + Array!bool linkswitchIsForCC; Array!(const(char)*) libfiles; Array!(const(char)*) dllfiles; const(char)[] deffile; diff --git a/src/dmd/link.d b/src/dmd/link.d index aa1441f24686..29d6f2a88e29 100644 --- a/src/dmd/link.d +++ b/src/dmd/link.d @@ -601,36 +601,13 @@ public int runLINK() */ // STEP 1 - if (global.params.noXlinker) // See https://issues.dlang.org/show_bug.cgi?id=6952 + foreach (pi, p; global.params.linkswitches) { - const(char)* prior; - foreach (p; global.params.linkswitches) + if (p && p[0] && !flagIsLibraryRelated(p)) { - // link switches with a prepended "-Xlinker" should be - // be pushed together to `linkerArgs` - - if (p && p[0] && strcmp(p, "-Xlinker") != 0) - { - if (!flagIsLibraryRelated(p)) - { - if (prior && prior[0] && strcmp(prior, "-Xlinker") == 0) - argv.push(prior); - argv.push(p); - } - } - - prior = p; - } - } - else - { - foreach (p; global.params.linkswitches) - { - if (p && p[0] && !flagIsLibraryRelated(p)) - { + if (!global.params.linkswitchIsForCC[pi]) argv.push("-Xlinker"); - argv.push(p); - } + argv.push(p); } } @@ -642,32 +619,19 @@ public int runLINK() } // STEP 3 - if (global.params.noXlinker) // See https://issues.dlang.org/show_bug.cgi?id=6952 - { - foreach (p; global.params.linkswitches) - { - if (p && p[0] && flagIsLibraryRelated(p)) - { - argv.push(p); - } - } - } - else + foreach (pi, p; global.params.linkswitches) { - foreach (p; global.params.linkswitches) + if (p && p[0] && flagIsLibraryRelated(p)) { - if (flagIsLibraryRelated(p)) + if (!startsWith(p, "-l") && !startsWith(p, "-L") && !global.params.linkswitchIsForCC[pi]) { - if (!startsWith(p, "-l") && !startsWith(p, "-L")) - { - // Don't need -Xlinker if switch starts with -l or -L. - // Eliding -Xlinker is significant for -L since it allows our paths - // to take precedence over gcc defaults. - // All other link switches were already added in step 1. - argv.push("-Xlinker"); - } - argv.push(p); + // Don't need -Xlinker if switch starts with -l or -L. + // Eliding -Xlinker is significant for -L since it allows our paths + // to take precedence over gcc defaults. + // All other link switches were already added in step 1. + argv.push("-Xlinker"); } + argv.push(p); } } diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 7272b98979c9..e86a1ccadac9 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -2143,6 +2143,19 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param goto Lerror; } } + else if (startsWith(p + 1, "Xcc=")) + { + // Linking code is guarded by version (Posix): + static if (TARGET.Linux || TARGET.OSX || TARGET.FreeBSD || TARGET.OpenBSD || TARGET.Solaris || TARGET.DragonFlyBSD) + { + params.linkswitches.push(p + 5); + params.linkswitchIsForCC.push(true); + } + else + { + goto Lerror; + } + } else if (p[1] == 'X') // https://dlang.org/dmd.html#switch-X { params.doJsonGeneration = true; @@ -2357,6 +2370,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param else if (p[1] == 'L') // https://dlang.org/dmd.html#switch-L { params.linkswitches.push(p + 2 + (p[2] == '=')); + params.linkswitchIsForCC.push(false); } else if (startsWith(p + 1, "defaultlib=")) // https://dlang.org/dmd.html#switch-defaultlib { diff --git a/test/dshell/test6952.d b/test/dshell/test6952.d index 671587c6635b..95ad89fd2ba0 100644 --- a/test/dshell/test6952.d +++ b/test/dshell/test6952.d @@ -10,9 +10,9 @@ void main() } auto cmd = shellExpand("$DMD" - ~ " -m$MODEL -of$OUTPUT_BASE/main$EXE -conf= -fPIC -g -v -preview=noXlinker" + ~ " -m$MODEL -of$OUTPUT_BASE/main$EXE -conf= -fPIC -g -v" ~ " -I$EXTRA_FILES/test6952/ -defaultlib=" - ~ " -L-nostartfiles -L-nostdlib -L-nodefaultlibs $EXTRA_FILES/test6952/main.d"); + ~ " -Xcc=-nostartfiles -Xcc=-nostdlib -Xcc=-nodefaultlibs $EXTRA_FILES/test6952/main.d"); // Remove DFLAGS environment variable. Everything we need is explicitly stated in // the command line above. @@ -27,8 +27,8 @@ void main() immutable lines = result.output.split("\n"); auto ccLine = lines.find!(a => a.startsWith("cc"))[0]; - // Due to the `-preview=noXlinker` switch, the arguments prefixed with `-L` should - // not have an additional `-Xlinker` prepended to them + // The arguments prefixed with `-Xcc` should not have an + // additional `-Xlinker` prepended to them assert(ccLine.find("-Xlinker -nostartfiles") == ""); assert(ccLine.find("-Xlinker -nostdlib") == ""); assert(ccLine.find("-Xlinker -nodefaultlibs") == "");