Index: lld/MachO/InputFiles.h =================================================================== --- lld/MachO/InputFiles.h +++ lld/MachO/InputFiles.h @@ -148,6 +148,7 @@ static bool classof(const InputFile *f) { return f->kind() == DylibKind; } + StringRef originalInstallName; StringRef installName; DylibFile *exportingFile = nullptr; DylibFile *umbrella; Index: lld/MachO/InputFiles.cpp =================================================================== --- lld/MachO/InputFiles.cpp +++ lld/MachO/InputFiles.cpp @@ -847,7 +847,7 @@ auto *c = reinterpret_cast(cmd); currentVersion = read32le(&c->dylib.current_version); compatibilityVersion = read32le(&c->dylib.compatibility_version); - installName = + installName = originalInstallName = reinterpret_cast(cmd) + read32le(&c->dylib.name); } else if (!isBundleLoader) { // macho_executable and macho_bundle don't have LC_ID_DYLIB, @@ -938,7 +938,7 @@ umbrella = this; this->umbrella = umbrella; - installName = saver.save(interface.getInstallName()); + installName = originalInstallName= saver.save(interface.getInstallName()); compatibilityVersion = interface.getCompatibilityVersion().rawValue(); currentVersion = interface.getCurrentVersion().rawValue(); Index: lld/MachO/Writer.cpp =================================================================== --- lld/MachO/Writer.cpp +++ lld/MachO/Writer.cpp @@ -629,6 +629,25 @@ return it == minVersion.end() ? true : platformInfo.minimum >= it->second; } +static void updateDylibVersions() { + // For dylibs that had their installName updated later, updates + // compatibilityVersion and currentVersion from the dylib that + // originally had that installName. + DenseMap dylibForInstallName; + for (InputFile *file : inputFiles) + if (auto *dylibFile = dyn_cast(file)) + dylibForInstallName[dylibFile->originalInstallName] = dylibFile; + for (InputFile *file : inputFiles) { + if (auto *dylibFile = dyn_cast(file)) { + auto it = dylibForInstallName.find(dylibFile->installName); + if (it != dylibForInstallName.end()) { + dylibFile->compatibilityVersion = it->second->compatibilityVersion; + dylibFile->currentVersion = it->second->currentVersion; + } + } + } +} + template void Writer::createLoadCommands() { uint8_t segIndex = 0; for (OutputSegment *seg : outputSegments) { @@ -672,6 +691,8 @@ else in.header->addLoadCommand(make(config->platformInfo)); + updateDylibVersions(); + int64_t dylibOrdinal = 1; DenseMap ordinalForInstallName; for (InputFile *file : inputFiles) { Index: lld/test/MachO/special-symbol-ld-install-name.s =================================================================== --- lld/test/MachO/special-symbol-ld-install-name.s +++ lld/test/MachO/special-symbol-ld-install-name.s @@ -8,14 +8,14 @@ ## since the specified version 11.0.0 matches the target version 11.0.0 # RUN: %lld -o %t/libfoo1.dylib %t/libLDInstallName.tbd %t/foo.o -dylib -platform_version macos 11.0.0 11.0.0 -# RUN: llvm-objdump --macho --dylibs-used %t/libfoo1.dylib | FileCheck --check-prefix=CASE1 %s +# RUN: llvm-otool -L %t/libfoo1.dylib | FileCheck --check-prefix=CASE1 %s # CASE1: /New (compatibility version 1.1.1, current version 5.0.0) ## Case 2: special symbol $ld$install_name does not affect the install name ## since the specified version 11.0.0 does not match the target version 12.0.0 # RUN: %lld -o %t/libfoo2.dylib %t/libLDInstallName.tbd %t/foo.o -dylib -platform_version macos 12.0.0 12.0.0 -# RUN: llvm-objdump --macho --dylibs-used %t/libfoo2.dylib | FileCheck --check-prefix=CASE2 %s +# RUN: llvm-otool -L %t/libfoo2.dylib | FileCheck --check-prefix=CASE2 %s # CASE2: /Old (compatibility version 1.1.1, current version 5.0.0) ## Check that we emit a warning for an invalid os version. @@ -25,6 +25,17 @@ # INVALID-VERSION: failed to parse os version, symbol '$ld$install_name$os11.a$/New' ignored +## Case 3: If there's another library that has '/New' as its original +## install_name, we should take current-version and compatibility-version from +## there. +# RUN: ld -o %t/libfoo3.dylib %t/libLDInstallNameNew.tbd %t/foo.o -dylib -platform_version macos 11.0.0 11.0.0 +# RUN: llvm-otool -L %t/libfoo3.dylib | FileCheck --check-prefix=CASE3 %s +# RUN: ld -o %t/libfoo3.dylib %t/libLDInstallName.tbd %t/libLDInstallNameNew.tbd %t/foo.o -dylib -platform_version macos 11.0.0 11.0.0 +# RUN: llvm-otool -L %t/libfoo3.dylib | FileCheck --check-prefix=CASE3 %s +# RUN: ld -o %t/libfoo3.dylib %t/libLDInstallNameNew.tbd %t/libLDInstallName.tbd %t/foo.o -dylib -platform_version macos 11.0.0 11.0.0 +# RUN: llvm-otool -L %t/libfoo3.dylib | FileCheck --check-prefix=CASE3 %s +# CASE3: /New (compatibility version 4.5.6, current version 9.0.0) + #--- foo.s .long _xxx@GOTPCREL @@ -53,3 +64,18 @@ - archs: [ x86_64 ] symbols: [ '$ld$install_name$os11.a$/New', _xxx ] ... + +#--- libLDInstallNameNew.tbd +--- !tapi-tbd +tbd-version: 4 +targets: [ x86_64-macos ] +uuids: + - target: x86_64-macos + value: 2E994C7F-3F03-3A07-879C-55690D22BEDA +install-name: '/New' +current-version: 9 +compatibility-version: 4.5.6 +reexported-libraries: + - targets: [ x86_64-macos ] + libraries: [ '@loader_path/libLDInstallName' ] +...