bool searchDylibsFirst = false;
bool saveTemps = false;
uint32_t headerPad;
+ uint32_t dylibCompatibilityVersion = 0;
+ uint32_t dylibCurrentVersion = 0;
llvm::StringRef installName;
llvm::StringRef outputFile;
llvm::StringRef ltoObjPath;
error(msg + ": " + StringRef(err).trim());
}
+static uint32_t parseDylibVersion(const opt::ArgList& args, unsigned id) {
+ const opt::Arg *arg = args.getLastArg(id);
+ if (!arg)
+ return 0;
+
+ if (config->outputType != MH_DYLIB) {
+ error(arg->getAsString(args) + ": only valid with -dylib");
+ return 0;
+ }
+
+ llvm::VersionTuple version;
+ if (version.tryParse(arg->getValue()) || version.getBuild().hasValue()) {
+ error(arg->getAsString(args) + ": malformed version");
+ return 0;
+ }
+
+ unsigned major = version.getMajor();
+ if (major > UINT16_MAX) {
+ error(arg->getAsString(args) + ": component " + Twine(major) +
+ " out of range");
+ return 0;
+ }
+
+ unsigned minor = version.getMinor().getValueOr(0);
+ if (minor > UINT8_MAX) {
+ error(arg->getAsString(args) + ": component " + Twine(minor) +
+ " out of range");
+ return 0;
+ }
+
+ unsigned subminor = version.getSubminor().getValueOr(0);
+ if (subminor > UINT8_MAX) {
+ error(arg->getAsString(args) + ": component " + Twine(subminor) +
+ " out of range");
+ return 0;
+ }
+
+ return (major << 16) | (minor << 8) | subminor;
+}
+
bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
raw_ostream &stdoutOS, raw_ostream &stderrOS) {
lld::stdoutOS = &stdoutOS;
config->searchDylibsFirst =
(arg && arg->getOption().getID() == OPT_search_dylibs_first);
+ config->dylibCompatibilityVersion =
+ parseDylibVersion(args, OPT_compatibility_version);
+ config->dylibCurrentVersion = parseDylibVersion(args, OPT_current_version);
+
config->saveTemps = args.hasArg(OPT_save_temps);
if (args.hasArg(OPT_v)) {
def compatibility_version : Separate<["-"], "compatibility_version">,
MetaVarName<"<version>">,
HelpText<"Compatibility <version> of this library">,
- Flags<[HelpHidden]>,
Group<grp_dylib>;
def dylib_compatibility_version : Separate<["-"], "dylib_compatibility_version">,
MetaVarName<"<version>">,
def current_version : Separate<["-"], "current_version">,
MetaVarName<"<version>">,
HelpText<"Current <version> of this library">,
- Flags<[HelpHidden]>,
Group<grp_dylib>;
def dylib_current_version : Separate<["-"], "dylib_current_version">,
MetaVarName<"<version>">,
// * LC_REEXPORT_DYLIB
class LCDylib : public LoadCommand {
public:
- LCDylib(LoadCommandType type, StringRef path) : type(type), path(path) {
+ LCDylib(LoadCommandType type, StringRef path,
+ uint32_t compatibilityVersion = 0, uint32_t currentVersion = 0)
+ : type(type), path(path), compatibilityVersion(compatibilityVersion),
+ currentVersion(currentVersion) {
instanceCount++;
}
c->cmd = type;
c->cmdsize = getSize();
c->dylib.name = sizeof(dylib_command);
+ c->dylib.timestamp = 0;
+ c->dylib.compatibility_version = compatibilityVersion;
+ c->dylib.current_version = currentVersion;
memcpy(buf, path.data(), path.size());
buf[path.size()] = '\0';
private:
LoadCommandType type;
StringRef path;
+ uint32_t compatibilityVersion;
+ uint32_t currentVersion;
static uint32_t instanceCount;
};
in.header->addLoadCommand(make<LCLoadDylinker>());
break;
case MH_DYLIB:
- in.header->addLoadCommand(make<LCDylib>(LC_ID_DYLIB, config->installName));
+ in.header->addLoadCommand(make<LCDylib>(LC_ID_DYLIB, config->installName,
+ config->dylibCompatibilityVersion,
+ config->dylibCurrentVersion));
break;
case MH_BUNDLE:
break;
--- /dev/null
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
+
+# RUN: not %lld -o %t/executable %t.o -o /dev/null \
+# RUN: -compatibility_version 10 -current_version 11 2>&1 | \
+# RUN: FileCheck --check-prefix=NEEDDYLIB %s
+# RUN: not %lld -execute -o %t/executable %t.o -o /dev/null \
+# RUN: -compatibility_version 10 -current_version 11 2>&1 | \
+# RUN: FileCheck --check-prefix=NEEDDYLIB %s
+# RUN: not %lld -bundle -o %t/executable %t.o -o /dev/null \
+# RUN: -compatibility_version 10 -current_version 11 2>&1 | \
+# RUN: FileCheck --check-prefix=NEEDDYLIB %s
+
+# NEEDDYLIB: error: -compatibility_version 10: only valid with -dylib
+# NEEDDYLIB: error: -current_version 11: only valid with -dylib
+
+# RUN: not %lld -dylib -o %t/executable %t.o -o /dev/null \
+# RUN: -compatibility_version 1.2.3.4 -current_version 1.2.3.4.5 2>&1 | \
+# RUN: FileCheck --check-prefix=MALFORMED %s
+
+# MALFORMED: error: -compatibility_version 1.2.3.4: malformed version
+# MALFORMED: error: -current_version 1.2.3.4.5: malformed version
+
+# RUN: not %lld -dylib -o %t/executable %t.o -o /dev/null \
+# RUN: -compatibility_version 80000.1 -current_version 1.2.3 2>&1 | \
+# RUN: FileCheck --check-prefix=BADMAJOR %s
+
+# BADMAJOR: error: -compatibility_version 80000.1: component 80000 out of range
+
+# RUN: not %lld -dylib -o %t/executable %t.o -o /dev/null \
+# RUN: -compatibility_version 8.300 -current_version 1.2.3 2>&1 | \
+# RUN: FileCheck --check-prefix=BADMINOR %s
+
+# BADMINOR: error: -compatibility_version 8.300: component 300 out of range
+
+# RUN: not %lld -dylib -o %t/executable %t.o -o /dev/null \
+# RUN: -compatibility_version 8.8.300 -current_version 1.2.3 2>&1 | \
+# RUN: FileCheck --check-prefix=BADSUBMINOR %s
+
+# BADSUBMINOR: error: -compatibility_version 8.8.300: component 300 out of range
+
+# RUN: %lld -dylib -o %t/executable %t.o -o %t.dylib \
+# RUN: -compatibility_version 1.2.3 -current_version 2.5.6
+# RUN: llvm-objdump --macho --all-headers %t.dylib | FileCheck %s
+
+# CHECK: cmd LC_ID_DYLIB
+# CHECK-NEXT: cmdsize
+# CHECK-NEXT: name
+# CHECK-NEXT: time stamp
+# CHECK-NEXT: current version 2.5.6
+# CHECK-NEXT: compatibility version 1.2.3
+
+.text
+.global _foo
+_foo:
+ mov $0, %rax
+ ret