unknown,
eof,
identifier,
+ libname,
comma,
l_paren,
r_paren,
struct Path {
StringRef _path;
bool _asNeeded;
+ bool _isDashlPrefix;
- Path() : _asNeeded(false) {}
- explicit Path(StringRef path, bool asNeeded = false)
- : _path(path), _asNeeded(asNeeded) {}
+ Path() : _asNeeded(false), _isDashlPrefix(false) {}
+ explicit Path(StringRef path, bool asNeeded = false, bool isLib = false)
+ : _path(path), _asNeeded(asNeeded), _isDashlPrefix(isLib) {}
};
class Group : public Command {
first = false;
if (path._asNeeded)
os << "AS_NEEDED(";
+ if (path._isDashlPrefix)
+ os << "-l";
os << path._path;
if (path._asNeeded)
os << ")";
for (const script::Path &path : group->getPaths()) {
// TODO : Propagate Set WholeArchive/dashlPrefix
attributes.setAsNeeded(path._asNeeded);
+ attributes.setDashlPrefix(path._isDashlPrefix);
auto inputNode = new ELFFileNode(
_elfLinkingContext, _elfLinkingContext.allocateString(path._path),
attributes);
}
ErrorOr<StringRef> ELFLinkingContext::searchLibrary(StringRef libName) const {
+ bool hasColonPrefix = libName[0] == ':';
+ Twine soName =
+ hasColonPrefix ? libName.drop_front() : Twine("lib", libName) + ".so";
+ Twine archiveName =
+ hasColonPrefix ? libName.drop_front() : Twine("lib", libName) + ".a";
SmallString<128> path;
for (StringRef dir : _inputSearchPaths) {
// Search for dynamic library
if (!_isStaticExecutable) {
buildSearchPath(path, dir, _sysrootPath);
- llvm::sys::path::append(path, Twine("lib") + libName + ".so");
+ llvm::sys::path::append(path, soName);
if (llvm::sys::fs::exists(path.str()))
return StringRef(*new (_allocator) std::string(path.str()));
}
// Search for static libraries too
buildSearchPath(path, dir, _sysrootPath);
- llvm::sys::path::append(path, Twine("lib") + libName + ".a");
+ llvm::sys::path::append(path, archiveName);
if (llvm::sys::fs::exists(path.str()))
return StringRef(*new (_allocator) std::string(path.str()));
}
break;
CASE(eof)
CASE(identifier)
+ CASE(libname)
CASE(kw_as_needed)
CASE(kw_entry)
CASE(kw_group)
_buffer = _buffer.drop_front(quotedStringEnd + 1);
return;
}
+ // -l<lib name>
+ if (_buffer.startswith("-l")) {
+ _buffer = _buffer.drop_front(2);
+ StringRef::size_type start = 0;
+ if (_buffer[start] == ':')
+ ++start;
+ if (!canStartName(_buffer[start]))
+ // Create 'unknown' token.
+ break;
+ auto libNameEnd =
+ std::find_if(_buffer.begin() + start + 1, _buffer.end(),
+ [=](char c) { return !canContinueName(c); });
+ StringRef::size_type libNameLen =
+ std::distance(_buffer.begin(), libNameEnd);
+ tok = Token(_buffer.substr(0, libNameLen), Token::libname);
+ _buffer = _buffer.drop_front(libNameLen);
+ return;
+ }
/// keyword or identifer.
if (!canStartName(_buffer[0]))
break;
std::vector<Path> paths;
- while (_tok._kind == Token::identifier || _tok._kind == Token::kw_as_needed) {
+ while (_tok._kind == Token::identifier || _tok._kind == Token::libname ||
+ _tok._kind == Token::kw_as_needed) {
switch (_tok._kind) {
case Token::identifier:
paths.push_back(Path(_tok._range));
consumeToken();
break;
+ case Token::libname:
+ paths.push_back(Path(_tok._range, false, true));
+ consumeToken();
+ break;
case Token::kw_as_needed:
if (!parseAsNeeded(paths))
return nullptr;
if (!expectAndConsume(Token::l_paren, "expected ("))
return false;
- while (_tok._kind == Token::identifier) {
- paths.push_back(Path(_tok._range, true));
- consumeToken();
+ while (_tok._kind == Token::identifier || _tok._kind == Token::libname) {
+ switch (_tok._kind) {
+ case Token::identifier:
+ paths.push_back(Path(_tok._range, true, false));
+ consumeToken();
+ break;
+ case Token::libname:
+ paths.push_back(Path(_tok._range, true, true));
+ consumeToken();
+ break;
+ default:
+ llvm_unreachable("Invalid token.");
+ }
}
if (!expectAndConsume(Token::r_paren, "expected )"))
--- /dev/null
+/* RUN: linker-script-test %s 2>&1 | FileCheck %s
+*/
+
+OUTPUT_ARCH(i386:x86_64)
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+GROUP( -l### )
+ENTRY(init)
+
+/*
+CHECK: test/LinkerScript/libname-err-1.test:6:10: error: expected )
+*/
--- /dev/null
+/* RUN: linker-script-test %s 2>&1 | FileCheck %s
+*/
+
+OUTPUT_ARCH(i386:x86_64)
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+GROUP( -l )
+ENTRY(init)
+
+/*
+CHECK: test/LinkerScript/libname-err-2.test:6:10: error: expected )
+*/
OUTPUT_ARCH(i386:x86_64)
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
-GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) )
+GROUP ( /lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED ( /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 ) -lm -l:libgcc.a )
ENTRY(init)
/*
CHECK: l_paren: (
CHECK: identifier: /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
CHECK: r_paren: )
+CHECK: libname: m
+CHECK: libname: :libgcc.a
CHECK: r_paren: )
CHECK: kw_entry: ENTRY
CHECK: l_paren: (
CHECK: r_paren: )
CHECK: eof:
CHECK: OUTPUT_FORMAT(elf64-x86-64,elf64-x86-64,elf64-x86-64)
-CHECK: GROUP(/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED(/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2))
+CHECK: GROUP(/lib/x86_64-linux-gnu/libc.so.6 /usr/lib/x86_64-linux-gnu/libc_nonshared.a AS_NEEDED(/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2) -lm -l:libgcc.a)
CHECK: ENTRY(init)
*/
--- /dev/null
+GROUP ( -l:shared.so-x86-64 -lfnarchive )
*/
/*
+ This link should finish successfully. The group-cmd-search-3.ls
+ script contains GROUP command with two elements. The first one
+ has a -l:<path> form and should be found by iterating through
+ lib dirs and searching the 'path' name exactly. The second element
+ has a -l<lib name> form and should be found by constructing a full
+ library name lib<lib name>.a and iterating through lib dirs.
+
+RUN: lld -flavor gnu -target x86_64 -shared \
+RUN: -L%p/Inputs %p/Inputs/use-shared.x86-64 \
+RUN: %p/Inputs/group-cmd-search-3.ls -o %t8
+*/
+
+/*
This link should fail with unknown input file format error.
The linker script from this file contains GROUP with an absolute
path which can be found under provided sysroot directory.