From 5f39c844895f4709ee6a33317968e8ccfda0356b Mon Sep 17 00:00:00 2001 From: Parth Arora Date: Wed, 18 Mar 2026 02:01:15 -0700 Subject: [PATCH] Expand =/$SYSROOT for INPUT/GROUP script commands This commit improves the script parser to expand the = and $SYSROOT prefix in INPUT/GROUP inputs. Resolves #927 Signed-off-by: Parth Arora --- .../sysroot.rst.in | 9 ++++ include/eld/Diagnostics/DiagVerbose.inc | 2 + include/eld/Input/Input.h | 8 +++ lib/Input/Input.cpp | 30 +++++++++-- lib/Input/InputAction.cpp | 9 +++- lib/ScriptParser/ScriptParser.cpp | 3 +- .../linkerscript/SysrootExpansion/Inputs/1.c | 1 + .../SysrootExpansion/Inputs/group_equals.t | 1 + .../SysrootExpansion/Inputs/group_sysroot.t | 1 + .../SysrootExpansion/Inputs/main.c | 1 + .../SysrootExpansion/Inputs/script_equals.t | 1 + .../SysrootExpansion/Inputs/script_sysroot.t | 1 + .../SysrootExpansion/SysrootExpansion.test | 53 +++++++++++++++++++ 13 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 test/Common/standalone/linkerscript/SysrootExpansion/Inputs/1.c create mode 100644 test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_equals.t create mode 100644 test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_sysroot.t create mode 100644 test/Common/standalone/linkerscript/SysrootExpansion/Inputs/main.c create mode 100644 test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_equals.t create mode 100644 test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_sysroot.t create mode 100644 test/Common/standalone/linkerscript/SysrootExpansion/SysrootExpansion.test diff --git a/docs/userguide/CommandLineOptionsSupplements/sysroot.rst.in b/docs/userguide/CommandLineOptionsSupplements/sysroot.rst.in index a84de0303..1546be842 100644 --- a/docs/userguide/CommandLineOptionsSupplements/sysroot.rst.in +++ b/docs/userguide/CommandLineOptionsSupplements/sysroot.rst.in @@ -6,6 +6,15 @@ The files specified using the INPUT and GROUP command are searched inside the sy - The file begins with the ``/`` character, and - The script containing the INPUT/GROUP command is located within the sysroot directory. +Additionally, paths in INPUT/GROUP commands or on the command line can explicitly +force sysroot expansion by using the ``=`` or ``$SYSROOT`` prefix: + + - ``=/path/to/file`` expands to ``/path/to/file`` + - ``$SYSROOT/path/to/file`` expands to ``/path/to/file`` + +This works for both linker script commands and command-line input files. +If no sysroot is configured, the prefix is stripped and the remaining path is used. + :option:`-L` ```` When ```` is prefixed with ``=``, then ``=`` is expanded to the sysroot. \ No newline at end of file diff --git a/include/eld/Diagnostics/DiagVerbose.inc b/include/eld/Diagnostics/DiagVerbose.inc index 9ed9e081f..625bfce83 100644 --- a/include/eld/Diagnostics/DiagVerbose.inc +++ b/include/eld/Diagnostics/DiagVerbose.inc @@ -168,3 +168,5 @@ DIAG(verbose_loaded_plugin_config, DiagnosticEngine::Verbose, DIAG(verbose_infer_target, DiagnosticEngine::Verbose, "Inferred target : %0") DIAG(verbose_sframe_log, DiagnosticEngine::Verbose, "SFrame Handling : %0") +DIAG(verbose_sysroot_expansion, DiagnosticEngine::Verbose, + "Expanded sysroot marker in path. '%0' -> '%1'") diff --git a/include/eld/Input/Input.h b/include/eld/Input/Input.h index 47eb9f6dc..63dd71988 100644 --- a/include/eld/Input/Input.h +++ b/include/eld/Input/Input.h @@ -62,6 +62,14 @@ class Input { /// Return a user-facing text representation of input type. static llvm::StringRef toString(InputType); + /// Expand '=' or '$SYSROOT' prefix in the path using the configured sysroot. + /// Returns the expanded path, or the original if no marker is present. + /// If a marker is present but no sysroot is configured, the marker is + /// stripped. Emits verbose_sysroot_expansion diagnostic when expansion occurs. + static std::string expandSysrootMarkers(llvm::StringRef Name, + const SearchDirs &PSearchDirs, + DiagnosticEngine &DiagEngine); + /// getFileName returns the FileName passed to the driver otherwise. const std::string getFileName() const { return FileName; } diff --git a/lib/Input/Input.cpp b/lib/Input/Input.cpp index 0fd094c1f..d2f076d3b 100644 --- a/lib/Input/Input.cpp +++ b/lib/Input/Input.cpp @@ -85,6 +85,25 @@ bool Input::isPathValid(const std::string &Path) const { return true; } +std::string Input::expandSysrootMarkers(llvm::StringRef Name, + const SearchDirs &PSearchDirs, + DiagnosticEngine &DiagEngine) { + llvm::StringRef Suffix; + if (Name.starts_with("=")) + Suffix = Name.substr(1); + else if (Name.starts_with("$SYSROOT")) + Suffix = Name.substr(strlen("$SYSROOT")); + else + return Name.str(); + + std::string ExpandedPath = Suffix.str(); + if (PSearchDirs.hasSysRoot()) + ExpandedPath = (PSearchDirs.sysroot().native() + Suffix).str(); + + DiagEngine.raise(Diag::verbose_sysroot_expansion) << Name << ExpandedPath; + return ExpandedPath; +} + /// \return True if path able to be resolved, otherwise false bool Input::resolvePath(const LinkerConfig &PConfig) { if (ResolvedPath) @@ -92,9 +111,14 @@ bool Input::resolvePath(const LinkerConfig &PConfig) { if (PConfig.options().hasMappingFile() && !isInternal()) return resolvePathMappingFile(PConfig); auto &PSearchDirs = PConfig.directories(); + + std::string ExpandedFileName = FileName; + if (Type == Input::InputType::Script || Type == Input::InputType::Default) + ExpandedFileName = expandSysrootMarkers(FileName, PSearchDirs, *DiagEngine); + switch (Type) { default: - ResolvedPath = eld::sys::fs::Path(FileName); + ResolvedPath = eld::sys::fs::Path(ExpandedFileName); break; case Input::Internal: ResolvedPath = eld::sys::fs::Path(FileName); @@ -103,11 +127,11 @@ bool Input::resolvePath(const LinkerConfig &PConfig) { if (Type == Input::Script) { if (shouldPrependSysrootToScriptInput(PConfig)) { ResolvedPath = PSearchDirs.sysroot(); - ResolvedPath->append(FileName); + ResolvedPath->append(ExpandedFileName); } if (!llvm::sys::fs::exists(ResolvedPath->native())) { const sys::fs::Path *P = - PSearchDirs.find(FileName, SearchDirs::SearchInputType::Script); + PSearchDirs.find(ExpandedFileName, SearchDirs::SearchInputType::Script); if (P != nullptr) ResolvedPath = *P; } diff --git a/lib/Input/InputAction.cpp b/lib/Input/InputAction.cpp index 5753fce3a..c3e30ee83 100644 --- a/lib/Input/InputAction.cpp +++ b/lib/Input/InputAction.cpp @@ -44,10 +44,15 @@ InputFileAction::InputFileAction(std::string Name, : InputAction(K, Printer), Name(Name), I(nullptr) {} bool InputFileAction::activate(InputBuilder &PBuilder) { + const LinkerConfig &Config = PBuilder.getLinkerConfig(); + std::string ExpandedName = Input::expandSysrootMarkers( + Name, Config.directories(), *Config.getDiagEngine()); + std::ifstream Is; - Is.open(Name.c_str(), std::ifstream::in); + Is.open(ExpandedName.c_str(), std::ifstream::in); if (!Is.good()) { - PBuilder.getDiagEngine()->raise(Diag::fatal_cannot_read_input) << Name; + PBuilder.getDiagEngine()->raise(Diag::fatal_cannot_read_input) + << ExpandedName; return false; } Is.close(); diff --git a/lib/ScriptParser/ScriptParser.cpp b/lib/ScriptParser/ScriptParser.cpp index e7c8e356f..9ba7d1886 100644 --- a/lib/ScriptParser/ScriptParser.cpp +++ b/lib/ScriptParser/ScriptParser.cpp @@ -744,9 +744,10 @@ void ScriptParser::addFile(StringRef Name) { if (Name.consume_front("-l")) InputStrTok = ThisScriptFile.createNameSpecToken(Name.str(), ThisScriptFile.asNeeded()); - else + else { InputStrTok = ThisScriptFile.createFileToken(Name.str(), ThisScriptFile.asNeeded()); + } ThisScriptFile.getCurrentStringList()->pushBack(InputStrTok); } diff --git a/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/1.c b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/1.c new file mode 100644 index 000000000..a60f28c10 --- /dev/null +++ b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/1.c @@ -0,0 +1 @@ +int foo() { return 1; } diff --git a/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_equals.t b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_equals.t new file mode 100644 index 000000000..8718c221c --- /dev/null +++ b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_equals.t @@ -0,0 +1 @@ +GROUP(=/lib64/lib1.so) diff --git a/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_sysroot.t b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_sysroot.t new file mode 100644 index 000000000..db8b73f37 --- /dev/null +++ b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/group_sysroot.t @@ -0,0 +1 @@ +GROUP($SYSROOT/lib64/lib1.so) diff --git a/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/main.c b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/main.c new file mode 100644 index 000000000..76e819701 --- /dev/null +++ b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/main.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_equals.t b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_equals.t new file mode 100644 index 000000000..7ba279c9e --- /dev/null +++ b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_equals.t @@ -0,0 +1 @@ +INPUT(=/lib64/lib1.so) diff --git a/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_sysroot.t b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_sysroot.t new file mode 100644 index 000000000..d95da50af --- /dev/null +++ b/test/Common/standalone/linkerscript/SysrootExpansion/Inputs/script_sysroot.t @@ -0,0 +1 @@ +INPUT($SYSROOT/lib64/lib1.so) diff --git a/test/Common/standalone/linkerscript/SysrootExpansion/SysrootExpansion.test b/test/Common/standalone/linkerscript/SysrootExpansion/SysrootExpansion.test new file mode 100644 index 000000000..11689f562 --- /dev/null +++ b/test/Common/standalone/linkerscript/SysrootExpansion/SysrootExpansion.test @@ -0,0 +1,53 @@ +#---SysrootExpansion.test---------------- Linker Script ----------------# +#BEGIN_COMMENT +# Validate sysroot expansion for "=" and "$SYSROOT" markers in INPUT/GROUP +# script commands and command-line object files. +#END_COMMENT +#START_TEST + +RUN: rm -rf %t.dir && mkdir -p %t.dir/lib64 +RUN: %clang %clangopts -o %t.1.o %p/Inputs/1.c -c -fPIC +RUN: %clang %clangopts -o %t.main.o %p/Inputs/main.c -c + +# Create shared library in sysroot +RUN: %link %linkopts -o %t.dir/lib64/lib1.so -shared %t.1.o + +# Test INPUT with = prefix +RUN: %link %linkopts -o %t.out1 --sysroot=%t.dir -T %p/Inputs/script_equals.t %t.main.o --verbose 2>&1 | %filecheck %s --check-prefix=EQUALS + +# Test INPUT with $SYSROOT prefix +RUN: %link %linkopts -o %t.out2 --sysroot=%t.dir -T %p/Inputs/script_sysroot.t %t.main.o --verbose 2>&1 | %filecheck %s --check-prefix=SYSROOT + +# Test GROUP with = prefix +RUN: %link %linkopts -o %t.out3 --sysroot=%t.dir -T %p/Inputs/group_equals.t %t.main.o --verbose 2>&1 | %filecheck %s --check-prefix=GROUP_EQUALS + +# Test GROUP with $SYSROOT prefix +RUN: %link %linkopts -o %t.out4 --sysroot=%t.dir -T %p/Inputs/group_sysroot.t %t.main.o --verbose 2>&1 | %filecheck %s --check-prefix=GROUP_SYSROOT + +# Test = prefix without sysroot set (should fail) +RUN: %not %link %linkopts -o %t.out5 -T %p/Inputs/script_equals.t %t.main.o 2>&1 | %filecheck %s --check-prefix=NOSYSROOT + +# Copy object file to sysroot for command-line tests +RUN: cp %t.main.o %t.dir/lib64/main.o + +# Test command-line object file with = prefix +RUN: %link %linkopts -o %t.out6 --sysroot=%t.dir %t.1.o =/lib64/main.o --verbose 2>&1 | %filecheck %s --check-prefix=CMDLINE_EQUALS + +# Test command-line object file with $SYSROOT prefix +RUN: %link %linkopts -o %t.out7 --sysroot=%t.dir %t.1.o '$SYSROOT/lib64/main.o' --verbose 2>&1 | %filecheck %s --check-prefix=CMDLINE_SYSROOT + +# Test verbose diagnostic for sysroot expansion +RUN: %link %linkopts -o %t.out8 --sysroot=%t.dir -T %p/Inputs/script_equals.t %t.main.o --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_DIAG +RUN: %link %linkopts -o %t.out9 --sysroot=%t.dir %t.1.o =/lib64/main.o --verbose 2>&1 | %filecheck %s --check-prefix=VERBOSE_CMDLINE + +#END_TEST + +EQUALS: Verbose: Mapping input file '{{.*}}dir/lib64/lib1.so' into memory +SYSROOT: Verbose: Mapping input file '{{.*}}dir/lib64/lib1.so' into memory +GROUP_EQUALS: Verbose: Mapping input file '{{.*}}dir/lib64/lib1.so' into memory +GROUP_SYSROOT: Verbose: Mapping input file '{{.*}}dir/lib64/lib1.so' into memory +NOSYSROOT: Fatal: cannot read file /lib64/lib1.so +CMDLINE_EQUALS: Verbose: Mapping input file '{{.*}}dir/lib64/main.o' into memory +CMDLINE_SYSROOT: Verbose: Mapping input file '{{.*}}dir/lib64/main.o' into memory +VERBOSE_DIAG: Verbose: Expanded sysroot marker in path. '=/lib64/lib1.so' -> '{{.*}}dir/lib64/lib1.so' +VERBOSE_CMDLINE: Verbose: Expanded sysroot marker in path. '=/lib64/main.o' -> '{{.*}}dir/lib64/main.o'