With -platform_version flags for two distinct platforms,
this writes a LC_BUILD_VERSION header for each.
The motivation is that this is needed for self-hosting with lld as linker
after D124059.
To create a zippered output at the clang driver level, pass
-target arm64-apple-macos -darwin-target-variant arm64-apple-ios-macabi
to create a zippered dylib.
(In Xcode's clang, `-darwin-target-variant` is spelled just `-target-variant`.)
(If you pass `-target arm64-apple-ios-macabi -target-variant arm64-apple-macos`
instead, ld64 crashes!)
This results in two -platform_version flags being passed to the linker.
ld64 also verifies that the iOS SDK version is at least 13.1. We don't do that
yet. But ld64 also does that for other platforms and we don't. So we need to
do that at some point, but not in this patch.
Only dylib and bundle outputs can be zippered.
I verified that a Catalyst app linked against a dylib created with
clang -shared foo.cc -o libfoo.dylib \
-target arm64-apple-macos \
-target-variant arm64-apple-ios-macabi \
-Wl,-install_name,@rpath/libfoo.dylib \
-fuse-ld=$PWD/out/gn/bin/ld64.lld
runs successfully. (The app calls a function `f()` in libfoo.dylib
that returns a const char* "foo", and NSLog(@"%s")s it.)
ld64 is a bit more permissive when writing zippered outputs,
see references to "unzippered twins". That's not implemented yet.
(If anybody wants to implement that, D124275 is a good start.)
Differential Revision: https://reviews.llvm.org/D124887
206 lines
5.8 KiB
C++
206 lines
5.8 KiB
C++
//===- Config.h -------------------------------------------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLD_MACHO_CONFIG_H
|
|
#define LLD_MACHO_CONFIG_H
|
|
|
|
#include "llvm/ADT/CachedHashString.h"
|
|
#include "llvm/ADT/DenseMap.h"
|
|
#include "llvm/ADT/DenseSet.h"
|
|
#include "llvm/ADT/MapVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/ADT/StringSet.h"
|
|
#include "llvm/BinaryFormat/MachO.h"
|
|
#include "llvm/Support/CachePruning.h"
|
|
#include "llvm/Support/GlobPattern.h"
|
|
#include "llvm/Support/VersionTuple.h"
|
|
#include "llvm/TextAPI/Architecture.h"
|
|
#include "llvm/TextAPI/Platform.h"
|
|
#include "llvm/TextAPI/Target.h"
|
|
|
|
#include <vector>
|
|
|
|
namespace lld {
|
|
namespace macho {
|
|
|
|
class InputSection;
|
|
class Symbol;
|
|
|
|
using NamePair = std::pair<llvm::StringRef, llvm::StringRef>;
|
|
using SectionRenameMap = llvm::DenseMap<NamePair, NamePair>;
|
|
using SegmentRenameMap = llvm::DenseMap<llvm::StringRef, llvm::StringRef>;
|
|
|
|
struct PlatformInfo {
|
|
llvm::MachO::Target target;
|
|
llvm::VersionTuple minimum;
|
|
llvm::VersionTuple sdk;
|
|
};
|
|
|
|
inline uint32_t encodeVersion(const llvm::VersionTuple &version) {
|
|
return ((version.getMajor() << 020) |
|
|
(version.getMinor().getValueOr(0) << 010) |
|
|
version.getSubminor().getValueOr(0));
|
|
}
|
|
|
|
enum class NamespaceKind {
|
|
twolevel,
|
|
flat,
|
|
};
|
|
|
|
enum class UndefinedSymbolTreatment {
|
|
unknown,
|
|
error,
|
|
warning,
|
|
suppress,
|
|
dynamic_lookup,
|
|
};
|
|
|
|
enum class ICFLevel {
|
|
unknown,
|
|
none,
|
|
safe,
|
|
all,
|
|
};
|
|
|
|
struct SectionAlign {
|
|
llvm::StringRef segName;
|
|
llvm::StringRef sectName;
|
|
uint32_t align;
|
|
};
|
|
|
|
struct SegmentProtection {
|
|
llvm::StringRef name;
|
|
uint32_t maxProt;
|
|
uint32_t initProt;
|
|
};
|
|
|
|
class SymbolPatterns {
|
|
public:
|
|
// GlobPattern can also match literals,
|
|
// but we prefer the O(1) lookup of DenseSet.
|
|
llvm::DenseSet<llvm::CachedHashStringRef> literals;
|
|
std::vector<llvm::GlobPattern> globs;
|
|
|
|
bool empty() const { return literals.empty() && globs.empty(); }
|
|
void clear();
|
|
void insert(llvm::StringRef symbolName);
|
|
bool matchLiteral(llvm::StringRef symbolName) const;
|
|
bool matchGlob(llvm::StringRef symbolName) const;
|
|
bool match(llvm::StringRef symbolName) const;
|
|
};
|
|
|
|
struct Configuration {
|
|
Symbol *entry = nullptr;
|
|
bool hasReexports = false;
|
|
bool allLoad = false;
|
|
bool applicationExtension = false;
|
|
bool archMultiple = false;
|
|
bool exportDynamic = false;
|
|
bool forceLoadObjC = false;
|
|
bool forceLoadSwift = false;
|
|
bool staticLink = false;
|
|
bool implicitDylibs = false;
|
|
bool isPic = false;
|
|
bool headerPadMaxInstallNames = false;
|
|
bool markDeadStrippableDylib = false;
|
|
bool printDylibSearch = false;
|
|
bool printEachFile = false;
|
|
bool printWhyLoad = false;
|
|
bool searchDylibsFirst = false;
|
|
bool saveTemps = false;
|
|
bool adhocCodesign = false;
|
|
bool emitFunctionStarts = false;
|
|
bool emitBitcodeBundle = false;
|
|
bool emitDataInCodeInfo = false;
|
|
bool emitEncryptionInfo = false;
|
|
bool timeTraceEnabled = false;
|
|
bool dataConst = false;
|
|
bool dedupLiterals = true;
|
|
bool omitDebugInfo = false;
|
|
bool warnDylibInstallName = false;
|
|
uint32_t headerPad;
|
|
uint32_t dylibCompatibilityVersion = 0;
|
|
uint32_t dylibCurrentVersion = 0;
|
|
uint32_t timeTraceGranularity = 500;
|
|
unsigned optimize;
|
|
std::string progName;
|
|
|
|
// For `clang -arch arm64 -arch x86_64`, clang will:
|
|
// 1. invoke the linker twice, to write one temporary output per arch
|
|
// 2. invoke `lipo` to merge the two outputs into a single file
|
|
// `outputFile` is the name of the temporary file the linker writes to.
|
|
// `finalOutput `is the name of the file lipo writes to after the link.
|
|
llvm::StringRef outputFile;
|
|
llvm::StringRef finalOutput;
|
|
|
|
llvm::StringRef installName;
|
|
llvm::StringRef mapFile;
|
|
llvm::StringRef ltoObjPath;
|
|
llvm::StringRef thinLTOJobs;
|
|
llvm::StringRef umbrella;
|
|
uint32_t ltoo = 2;
|
|
llvm::CachePruningPolicy thinLTOCachePolicy;
|
|
llvm::StringRef thinLTOCacheDir;
|
|
bool deadStripDylibs = false;
|
|
bool demangle = false;
|
|
bool deadStrip = false;
|
|
bool errorForArchMismatch = false;
|
|
PlatformInfo platformInfo;
|
|
llvm::Optional<PlatformInfo> secondaryPlatformInfo;
|
|
NamespaceKind namespaceKind = NamespaceKind::twolevel;
|
|
UndefinedSymbolTreatment undefinedSymbolTreatment =
|
|
UndefinedSymbolTreatment::error;
|
|
ICFLevel icfLevel = ICFLevel::none;
|
|
llvm::MachO::HeaderFileType outputType;
|
|
std::vector<llvm::StringRef> systemLibraryRoots;
|
|
std::vector<llvm::StringRef> librarySearchPaths;
|
|
std::vector<llvm::StringRef> frameworkSearchPaths;
|
|
std::vector<llvm::StringRef> runtimePaths;
|
|
std::vector<std::string> astPaths;
|
|
std::vector<Symbol *> explicitUndefineds;
|
|
llvm::StringSet<> explicitDynamicLookups;
|
|
// There are typically few custom sectionAlignments or segmentProtections,
|
|
// so use a vector instead of a map.
|
|
std::vector<SectionAlign> sectionAlignments;
|
|
std::vector<SegmentProtection> segmentProtections;
|
|
|
|
bool callGraphProfileSort = false;
|
|
llvm::StringRef printSymbolOrder;
|
|
|
|
SectionRenameMap sectionRenameMap;
|
|
SegmentRenameMap segmentRenameMap;
|
|
|
|
SymbolPatterns exportedSymbols;
|
|
SymbolPatterns unexportedSymbols;
|
|
SymbolPatterns whyLive;
|
|
|
|
bool zeroModTime = false;
|
|
|
|
llvm::StringRef osoPrefix;
|
|
|
|
llvm::MachO::Architecture arch() const { return platformInfo.target.Arch; }
|
|
|
|
llvm::MachO::PlatformType platform() const {
|
|
return platformInfo.target.Platform;
|
|
}
|
|
};
|
|
|
|
// Whether to force-load an archive.
|
|
enum class ForceLoad {
|
|
Default, // Apply -all_load or -ObjC behaviors if those flags are enabled
|
|
Yes, // Always load the archive, regardless of other flags
|
|
No, // Never load the archive, regardless of other flags
|
|
};
|
|
|
|
extern std::unique_ptr<Configuration> config;
|
|
|
|
} // namespace macho
|
|
} // namespace lld
|
|
|
|
#endif
|