objOpts.subType = _options.subArchitecture();
objOpts.platform = _options.platform();
objOpts.minOSVersion = _options.minOSversion();
- // workaround for strip -S
- // when ld -r has single input file, set the srcKind to kSourceSingle so __LLVM segment will be kept
- if (_options.outputKind() == Options::kObjectFile && _options.getInputFiles().size() == 1)
- objOpts.srcKind = ld::relocatable::File::kSourceSingle;
- else
- objOpts.srcKind = ld::relocatable::File::kSourceObj;
+ objOpts.srcKind = ld::relocatable::File::kSourceObj;
+ objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
+ objOpts.usingBitcode = _options.bundleBitcode();
+
ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts);
if ( objResult != NULL ) {
OSAtomicAdd64(len, &_totalObjectSize);
archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
else
archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
+ archOpts.objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData;
+ archOpts.objOpts.usingBitcode = _options.bundleBitcode();
+
ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts);
if ( archiveResult != NULL ) {
OSAtomicAdd64(len, &_totalArchiveSize);
fMarkAppExtensionSafe(false), fCheckAppExtensionSafe(false), fForceLoadSwiftLibs(false),
fSharedRegionEncodingV2(false), fUseDataConstSegment(false),
fUseDataConstSegmentForceOn(false), fUseDataConstSegmentForceOff(false),
- fBundleBitcode(false), fHideSymbols(false), fReverseMapUUIDRename(false), fReverseMapPath(NULL), fLTOCodegenOnly(false),
- fIgnoreAutoLink(false), fPlatform(kPlatformUnknown),
- fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
+ fBundleBitcode(false), fHideSymbols(false), fVerifyBitcode(false),
+ fReverseMapUUIDRename(false), fReverseMapPath(NULL), fLTOCodegenOnly(false),
+ fIgnoreAutoLink(false), fAllowDeadDups(false), fBitcodeKind(kBitcodeProcess),
+ fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset),
fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1)
if ( !fBundleBitcode )
warning("-bitcode_hide_symbols is ignored without -bitcode_bundle");
}
+ else if ( strcmp(arg, "-bitcode_verify") == 0 ) {
+ fVerifyBitcode = true;
+ if ( !fBundleBitcode )
+ warning("-bitcode_verify is ignored without -bitcode_bundle");
+ }
else if ( strcmp(arg, "-bitcode_symbol_map") == 0) {
fReverseMapPath = argv[++i];
if ( fReverseMapPath == NULL )
else if ( strcmp(argv[i], "-ignore_auto_link") == 0) {
fIgnoreAutoLink = true;
}
+ else if ( strcmp(argv[i], "-allow_dead_duplicates") == 0) {
+ fAllowDeadDups = true;
+ }
+ else if ( strcmp(argv[i], "-bitcode_process_mode") == 0 ) {
+ const char* bitcode_type = argv[++i];
+ if ( bitcode_type == NULL )
+ throw "missing argument to -bitcode_process_mode";
+ else if ( strcmp(bitcode_type, "strip") == 0 )
+ fBitcodeKind = kBitcodeStrip;
+ else if ( strcmp(bitcode_type, "marker") == 0 )
+ fBitcodeKind = kBitcodeMarker;
+ else if ( strcmp(bitcode_type, "data") == 0 )
+ fBitcodeKind = kBitcodeAsData;
+ else if ( strcmp(bitcode_type, "bitcode") == 0 )
+ fBitcodeKind = kBitcodeProcess;
+ else
+ throw "unknown argument to -bitcode_process_mode {strip,marker,data,bitcode}";
+ }
else if ( strcmp(arg, "-rpath") == 0 ) {
const char* path = argv[++i];
if ( path == NULL )
if ( !fSegmentOrder.empty() && (fOutputKind != Options::kPreload) )
throw "-segment_order can only used used with -preload output";
+ if ( fBitcodeKind != kBitcodeProcess &&
+ fOutputKind != Options::kObjectFile ) {
+ throw "-bitcode_process_mode can only be used together with -r";
+ }
+ // auto fix up the process type for strip -S.
+ // when there is only one input and output type is object file, downgrade kBitcodeProcess to kBitcodeAsData.
+ if ( fOutputKind == Options::kObjectFile && fInputFiles.size() == 1 && fBitcodeKind == Options::kBitcodeProcess )
+ fBitcodeKind = Options::kBitcodeAsData;
+
// <rdar://problem/17598404> warn if building an embedded iOS dylib for pre-iOS 8
// <rdar://problem/18935714> How can we suppress "ld: warning: embedded dylibs/frameworks only run on iOS 8 or laterÓ when building XCTest?
if ( (fOutputKind == Options::kDynamicLibrary) && (fIOSVersionMin != ld::iOSVersionUnset) && (fDylibInstallName != NULL) ) {
enum CommonsMode { kCommonsIgnoreDylibs, kCommonsOverriddenByDylibs, kCommonsConflictsDylibsError };
enum UUIDMode { kUUIDNone, kUUIDRandom, kUUIDContent };
enum LocalSymbolHandling { kLocalSymbolsAll, kLocalSymbolsNone, kLocalSymbolsSelectiveInclude, kLocalSymbolsSelectiveExclude };
+ enum BitcodeMode { kBitcodeProcess, kBitcodeAsData, kBitcodeMarker, kBitcodeStrip };
enum DebugInfoStripping { kDebugInfoNone, kDebugInfoMinimal, kDebugInfoFull };
#if SUPPORT_APPLE_TV
enum Platform { kPlatformUnknown, kPlatformOSX, kPlatformiOS, kPlatformWatchOS, kPlatform_tvOS };
bool forceLoadSwiftLibs() const { return fForceLoadSwiftLibs; }
bool bundleBitcode() const { return fBundleBitcode; }
bool hideSymbols() const { return fHideSymbols; }
+ bool verifyBitcode() const { return fVerifyBitcode; }
bool renameReverseSymbolMap() const { return fReverseMapUUIDRename; }
const char* reverseSymbolMapPath() const { return fReverseMapPath; }
std::string reverseMapTempPath() const { return fReverseMapTempPath; }
bool ltoCodegenOnly() const { return fLTOCodegenOnly; }
bool ignoreAutoLink() const { return fIgnoreAutoLink; }
+ bool allowDeadDuplicates() const { return fAllowDeadDups; }
+ BitcodeMode bitcodeKind() const { return fBitcodeKind; }
bool sharedRegionEncodingV2() const { return fSharedRegionEncodingV2; }
bool useDataConstSegment() const { return fUseDataConstSegment; }
bool hasWeakBitTweaks() const;
bool fUseDataConstSegmentForceOff;
bool fBundleBitcode;
bool fHideSymbols;
+ bool fVerifyBitcode;
bool fReverseMapUUIDRename;
const char* fReverseMapPath;
std::string fReverseMapTempPath;
bool fLTOCodegenOnly;
bool fIgnoreAutoLink;
+ bool fAllowDeadDups;
+ BitcodeMode fBitcodeKind;
Platform fPlatform;
DebugInfoStripping fDebugInfoStripping;
const char* fTraceOutputFile;
this->doLinkerOption(*it, file.path());
}
}
-
// Resolve bitcode section in the object file
if ( _options.bundleBitcode() ) {
if ( objFile->getBitcode() == NULL ) {
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
break;
case Options::kPlatformWatchOS:
+#if SUPPORT_APPLE_TV
+ case Options::kPlatform_tvOS:
+#endif
throwf("'%s' does not contain bitcode. "
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
break;
- #if SUPPORT_APPLE_TV
- case Options::kPlatform_tvOS:
- warning("URGENT: all bitcode will be dropped because '%s' was built without bitcode. "
- "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor. "
- "Note: This will be an error in the future.", file.path());
- _internal.filesWithBitcode.clear();
- _internal.dropAllBitcode = true;
- break;
- #endif
}
}
} else {
// contains bitcode, check if it is just a marker
if ( objFile->getBitcode()->isMarker() ) {
- // if the bitcode is just a marker,
- // the executable will be created without bitcode section.
- // Otherwise, create a marker.
- if ( _options.outputKind() != Options::kDynamicExecutable &&
- _options.outputKind() != Options::kStaticExecutable )
- _internal.embedMarkerOnly = true;
- // Issue a warning if the marker is in the static library and filesWithBitcode is not empty.
- // That means there are object files actually compiled with full bitcode but the archive only has marker.
- // Don't warn on normal object files because it can be a debug build using archives with full bitcode.
- if ( !_internal.filesWithBitcode.empty() && objFile->sourceKind() == ld::relocatable::File::kSourceArchive )
- warning("full bitcode bundle could not be generated because '%s' was built only with bitcode marker. "
- "The library must be generated from Xcode archive build with bitcode enabled (Xcode setting ENABLE_BITCODE)", objFile->path());
+ // if -bitcode_verify_bundle is used, check if all the object files participate in the linking have full bitcode embedded.
+ // error on any marker encountered.
+ if ( _options.verifyBitcode() )
+ throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
+ "All object files and libraries for bitcode must be generated from Xcode Archive or Install build",
+ objFile->path());
+ // update the internal state that marker is encountered.
+ _internal.embedMarkerOnly = true;
_internal.filesWithBitcode.clear();
_internal.dropAllBitcode = true;
} else if ( !_internal.dropAllBitcode )
if ( dylibFile != NULL ) {
// Check dylib for bitcode, if the library install path is relative path or @rpath, it has to contain bitcode
if ( _options.bundleBitcode() ) {
- if ( dylibFile->getBitcode() == NULL &&
- dylibFile->installPath()[0] != '/' ) {
+ bool isSystemFramework = ( dylibFile->installPath() != NULL ) && ( dylibFile->installPath()[0] == '/' );
+ if ( dylibFile->getBitcode() == NULL && !isSystemFramework ) {
// Check if the dylib is from toolchain by checking the path
char tcLibPath[PATH_MAX];
char ldPath[PATH_MAX];
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target.", file.path());
break;
case Options::kPlatformWatchOS:
+#if SUPPORT_APPLE_TV
+ case Options::kPlatform_tvOS:
+#endif
throwf("'%s' does not contain bitcode. "
"You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor", file.path());
break;
- #if SUPPORT_APPLE_TV
- case Options::kPlatform_tvOS:
- warning("URGENT: all bitcode will be dropped because '%s' was built without bitcode. "
- "You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE) or obtain an updated library from the vendor. "
- "Note: This will be an error in the future.", file.path());
- _internal.filesWithBitcode.clear();
- _internal.dropAllBitcode = true;
- break;
- #endif
}
}
}
+ // Error on bitcode marker in non-system frameworks if -bitcode_verify is used
+ if ( _options.verifyBitcode() && !isSystemFramework &&
+ dylibFile->getBitcode() != NULL && dylibFile->getBitcode()->isMarker() )
+ throwf("bitcode bundle could not be generated because '%s' was built without full bitcode. "
+ "All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build",
+ dylibFile->path());
}
// update which form of ObjC dylibs are being linked
// tell symbol table about non-static atoms
if ( atom.scope() != ld::Atom::scopeTranslationUnit ) {
- _symbolTable.add(atom, _options.deadCodeStrip() && _completedInitialObjectFiles);
+ _symbolTable.add(atom, _options.deadCodeStrip() && (_completedInitialObjectFiles || _options.allowDeadDuplicates()));
// add symbol aliases defined on the command line
if ( _options.haveCmdLineAliases() ) {
{
public:
enum DebugInfoKind { kDebugInfoNone=0, kDebugInfoStabs=1, kDebugInfoDwarf=2, kDebugInfoStabsUUID=3 };
- enum SourceKind { kSourceUnknown=0, kSourceObj, kSourceLTO, kSourceArchive, kSourceCompilerArchive, kSourceSingle };
+ enum SourceKind { kSourceUnknown=0, kSourceObj, kSourceLTO, kSourceArchive, kSourceCompilerArchive };
struct Stab {
const class Atom* atom;
uint8_t type;
objOpts.platform = options.platform;
objOpts.subType = 0;
objOpts.srcKind = ld::relocatable::File::kSourceLTO;
+ objOpts.treateBitcodeAsData = false;
+ objOpts.usingBitcode = options.bitcodeBundle;
// mach-o parsing is done in-memory, but need path for debug notes
const char* path = "/tmp/lto.o";
Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX,
bool addVers, bool buildingForSimulator,
bool logAllFiles, const char* installPath,
- bool indirectDylib, bool ignoreMismatchPlatform);
+ bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode);
virtual ~File() {}
// overrides of ld::File
bool _installPathOverride;
bool _indirectDylibsProcessed;
bool _appExtensionSafe;
+ bool _usingBitcode;
uint32_t _minVersionInDylib;
uint32_t _platformInDylib;
std::unique_ptr<ld::Bitcode> _bitcode;
File<A>::File(const uint8_t* fileContent, uint64_t fileLength, const char* pth, time_t mTime, ld::File::Ordinal ord,
bool linkingFlatNamespace, bool linkingMainExecutable, bool hoistImplicitPublicDylibs,
Options::Platform platform, uint32_t linkMinOSVersion, bool allowSimToMacOSX, bool addVers, bool buildingForSimulator,
- bool logAllFiles, const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform)
+ bool logAllFiles, const char* targetInstallPath, bool indirectDylib, bool ignoreMismatchPlatform, bool usingBitcode)
: ld::dylib::File(strdup(pth), mTime, ord),
_platform(platform), _linkMinOSVersion(linkMinOSVersion), _allowSimToMacOSXLinking(allowSimToMacOSX), _addVersionLoadCommand(addVers),
_linkingFlat(linkingFlatNamespace), _implicitlyLinkPublicDylibs(hoistImplicitPublicDylibs),
_noRexports(false), _hasWeakExports(false),
_deadStrippable(false), _hasPublicInstallName(false),
_providedAtom(false), _explictReExportFound(false), _wrongOS(false), _installPathOverride(false),
- _indirectDylibsProcessed(false), _appExtensionSafe(false),
+ _indirectDylibsProcessed(false), _appExtensionSafe(false), _usingBitcode(usingBitcode),
_minVersionInDylib(0), _platformInDylib(Options::kPlatformUnknown)
{
const macho_header<P>* header = (const macho_header<P>*)fileContent;
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
// tvOS is a warning temporarily. rdar://problem/21746965
- if (platform == Options::kPlatform_tvOS)
+ if ( usingBitcode )
+ throwf("building for %s simulator, but linking against dylib built for %s,",
+ Options::platformName(platform),
+ Options::platformName(lcPlatform));
+ else
warning("URGENT: building for %s simulator, but linking against dylib (%s) built for %s. "
"Note: This will be an error in the future.",
Options::platformName(platform), path(),
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
// tvOS is a warning temporarily. rdar://problem/21746965
- if (platform == Options::kPlatform_tvOS)
+ if ( _usingBitcode )
+ throwf("building for %s, but linking against dylib built for %s,",
+ Options::platformName(platform),
+ Options::platformName(lcPlatform));
+ else
warning("URGENT: building for %s, but linking against dylib (%s) built for %s. "
"Note: This will be an error in the future.",
Options::platformName(platform), path(),
opts.logAllFiles(),
opts.installPath(),
indirectDylib,
- opts.outputKind() == Options::kPreload);
+ opts.outputKind() == Options::kPreload,
+ opts.bundleBitcode());
}
};
virtual uint8_t swiftVersion() const { return _swiftVersion; }
virtual ld::Bitcode* getBitcode() const { return _bitcode.get(); }
virtual SourceKind sourceKind() const { return _srcKind; }
- virtual void setSourceKind(SourceKind src) { _srcKind = src; }
const uint8_t* fileContent() { return _fileContent; }
private:
bool _verboseOptimizationHints;
bool _armUsesZeroCostExceptions;
bool _ignoreMismatchPlatform;
+ bool _treateBitcodeAsData;
+ bool _usingBitcode;
unsigned int _stubsSectionNum;
const macho_section<P>* _stubsMachOSection;
std::vector<const char*> _dtraceProviderInfo;
// create file object
_file = new File<A>(_path, _modTime, _fileContent, _ordinal);
- // set input source
- _file->setSourceKind(opts.srcKind);
+ // set sourceKind
+ _file->_srcKind = opts.srcKind;
+ // set treatBitcodeAsData
+ _treateBitcodeAsData = opts.treateBitcodeAsData;
+ _usingBitcode = opts.usingBitcode;
// respond to -t option
if ( opts.logAllFiles )
break;
#if SUPPORT_APPLE_TV
case Options::kPlatform_tvOS:
- // tvOS is a warning temporarily. rdar://problem/21746965
- if (platform == Options::kPlatform_tvOS)
+ // Error when using bitcocde, warning otherwise.
+ if (_usingBitcode)
+ throwf("building for %s%s, but linking in object file built for %s,",
+ Options::platformName(platform), (simulator ? " simulator" : ""),
+ Options::platformName(lcPlatform));
+ else
warning("URGENT: building for %s%s, but linking in object file (%s) built for %s. "
"Note: This will be an error in the future.",
Options::platformName(platform), (simulator ? " simulator" : ""), path(),
}
}
if ( strcmp(sect->segname(), "__LLVM") == 0 ) {
+ // Process bitcode segement
if ( strncmp(sect->sectname(), "__bitcode", 9) == 0 ) {
bitcodeSect = sect;
} else if ( strncmp(sect->sectname(), "__cmdline", 9) == 0 ) {
} else if ( strncmp(sect->sectname(), "__asm", 5) == 0 ) {
bitcodeAsm = true;
}
- // If it is not single input for ld -r, don't count the section
- // otherwise, fall through and add it to the sections.
- if (_file->sourceKind() != ld::relocatable::File::kSourceSingle)
+ // If treat the bitcode as data, continue to parse as a normal section.
+ if ( !_treateBitcodeAsData )
continue;
}
// ignore empty __OBJC sections
Options::Platform platform;
uint32_t minOSVersion;
ld::relocatable::File::SourceKind srcKind;
+ bool treateBitcodeAsData;
+ bool usingBitcode;
};
extern ld::relocatable::File* parse(const uint8_t* fileContent, uint64_t fileLength,
void BitcodeBundle::doPass()
{
- if ( _state.embedMarkerOnly ) {
- assert( _options.outputKind() != Options::kDynamicExecutable &&
- _options.outputKind() != Options::kStaticExecutable &&
- "Don't emit marker for executables");
- BitcodeAtom* marker = new BitcodeAtom();
- _state.addAtom(*marker);
+ if ( _options.bitcodeKind() == Options::kBitcodeStrip ||
+ _options.bitcodeKind() == Options::kBitcodeAsData )
+ // if emit no bitcode or emit bitcode segment as data, no need to generate bundle.
+ return;
+ else if ( _state.embedMarkerOnly || _options.bitcodeKind() == Options::kBitcodeMarker ) {
+ // if the bitcode is just a marker,
+ // the executable will be created without bitcode section.
+ // Otherwise, create a marker.
+ if( _options.outputKind() != Options::kDynamicExecutable &&
+ _options.outputKind() != Options::kStaticExecutable ) {
+ BitcodeAtom* marker = new BitcodeAtom();
+ _state.addAtom(*marker);
+ }
return;
}
throwf("could not add SDK version to bitcode bundle");
// Write dylibs
- const char* sdkRoot = NULL;
- if ( !_options.sdkPaths().empty() )
- sdkRoot = _options.sdkPaths().front();
+ char sdkRoot[PATH_MAX];
+ if ( _options.sdkPaths().empty() || (realpath(_options.sdkPaths().front(), sdkRoot) == NULL) )
+ strcpy(sdkRoot, "/");
if ( !_state.dylibs.empty() ) {
- std::vector<const char*> SDKPaths = _options.sdkPaths();
char dylibPath[PATH_MAX];
for ( auto &dylib : _state.dylibs ) {
- // For every dylib/framework, figure out if it is coming from a SDK
- // if it is coming from some SDK, we parse the path to figure out which SDK
- // If -syslibroot is pointing to a SDK, it should end with PlatformX.Y.sdk/
- if (sdkRoot && strncmp(dylib->path(), sdkRoot, strlen(sdkRoot)) == 0) {
- // dylib/framework from one of the -syslibroot
+ // For every dylib/framework, figure out if it is coming from a SDK.
+ // The dylib/framework from SDK must begin with '/' and user framework must begin with '@'.
+ if (dylib->installPath()[0] == '/') {
+ // Verify the path of the framework is within the SDK.
+ char dylibRealPath[PATH_MAX];
+ if ( realpath(dylib->path(), dylibRealPath) != NULL && strncmp(sdkRoot, dylibRealPath, strlen(sdkRoot)) != 0 )
+ warning("%s has install name beginning with \"/\" but it is not from the specified SDK", dylib->path());
// The path start with a string template
- strcpy(dylibPath, "{SDKPATH}/");
+ strcpy(dylibPath, "{SDKPATH}");
// append the path of dylib/frameowrk in the SDK
- strcat(dylibPath, dylib->path() + strlen(sdkRoot));
+ strcat(dylibPath, dylib->installPath());
} else {
// Not in any SDKs, then assume it is a user dylib/framework
// strip off all the path in the front
objOpts.verboseOptimizationHints = true;
objOpts.armUsesZeroCostExceptions = true;
objOpts.subType = sPreferredSubArch;
- objOpts.srcKind = ld::relocatable::File::kSourceObj;
+ objOpts.treateBitcodeAsData = false;
+ objOpts.usingBitcode = true;
#if 1
if ( ! foundFatSlice ) {
cpu_type_t archOfObj;