Skip to content

Commit d35242e

Browse files
committed
Initial implementation of FHS installed and freestanding bundles proposal
1 parent 414ebff commit d35242e

File tree

6 files changed

+381
-52
lines changed

6 files changed

+381
-52
lines changed

CoreFoundation/Base.subproj/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ module CoreFoundation [extern_c] [system] {
22
umbrella header "CoreFoundation.h"
33
explicit module CFPlugInCOM { header "CFPlugInCOM.h" }
44

5+
explicit module Private { header "CFPriv.h" }
56
}

CoreFoundation/PlugIn.subproj/CFBundle.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle")
118118
// Keys used by NSBundle for loaded Info plists.
119119
CONST_STRING_DECL(_kCFBundlePrincipalClassKey, "NSPrincipalClass")
120120

121+
121122
static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID;
122123

123124
static pthread_mutex_t CFBundleGlobalDataLock = PTHREAD_MUTEX_INITIALIZER;
@@ -136,6 +137,39 @@ static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths);
136137

137138
#pragma mark -
138139

140+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
141+
#define _CFBundleFHSDirectory_share CFSTR("share")
142+
143+
CF_INLINE Boolean _CFBundleURLIsForFHSInstalledBundle(CFURLRef bundleURL) {
144+
// Paths of this form are FHS installed bundles:
145+
// <anywhere>/share/<name>.resources
146+
147+
CFStringRef extension = CFURLCopyPathExtension(bundleURL);
148+
CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(NULL, bundleURL);
149+
CFStringRef containingDirectoryName = parentURL ? CFURLCopyLastPathComponent(parentURL) : NULL;
150+
151+
Boolean isFHSBundle =
152+
extension &&
153+
containingDirectoryName &&
154+
CFEqual(extension, _CFBundleSiblingResourceDirectoryExtension) &&
155+
CFEqual(containingDirectoryName, _CFBundleFHSDirectory_share);
156+
157+
if (extension) CFRelease(extension);
158+
if (parentURL) CFRelease(parentURL);
159+
if (containingDirectoryName) CFRelease(containingDirectoryName);
160+
161+
return isFHSBundle;
162+
}
163+
#endif // CFBUNDLE_ALLOW_FHS_BUNDLES
164+
165+
Boolean _CFBundleSupportsFHSBundles() {
166+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
167+
return true;
168+
#else
169+
return false;
170+
#endif
171+
}
172+
139173
CF_PRIVATE os_log_t _CFBundleResourceLogger(void) {
140174
static os_log_t _log;
141175
static dispatch_once_t onceToken;
@@ -677,6 +711,10 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL,
677711
}
678712

679713
bundle->_url = newURL;
714+
715+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
716+
bundle->_isFHSInstalledBundle = _CFBundleURLIsForFHSInstalledBundle(newURL);
717+
#endif
680718

681719
bundle->_version = localVersion;
682720
bundle->_infoDict = NULL;

CoreFoundation/PlugIn.subproj/CFBundlePriv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ CFBundleRefNum _CFBundleOpenBundleResourceFork(CFBundleRef bundle); // deprecate
302302
CF_EXPORT
303303
void _CFBundleCloseBundleResourceFork(CFBundleRef bundle); // deprecated in favor of CFBundleCloseBundleResourceMap
304304

305+
CF_EXPORT
306+
Boolean _CFBundleSupportsFHSBundles(void);
307+
305308
CF_EXTERN_C_END
306309

307310
#endif /* ! __COREFOUNDATION_CFBUNDLEPRIV__ */

CoreFoundation/PlugIn.subproj/CFBundle_Executable.c

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,30 @@
1515
#include <dlfcn.h>
1616
#endif
1717

18+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
19+
#if __LP64__
20+
#define _CFBundleFHSArchDirectorySuffix "64"
21+
#else // !__LP64__
22+
#define _CFBundleFHSArchDirectorySuffix "32"
23+
#endif // __LP64__
24+
25+
CONST_STRING_DECL(_CFBundleFHSDirectory_bin, "bin");
26+
CONST_STRING_DECL(_CFBundleFHSDirectory_sbin, "sbin");
27+
CONST_STRING_DECL(_CFBundleFHSDirectory_libWithArchSuffix, "lib" _CFBundleFHSArchDirectorySuffix);
28+
CONST_STRING_DECL(_CFBundleFHSDirectory_lib, "lib");
29+
30+
#define _CFBundleFHSExecutablesDirectorySuffix CFSTR(".executables")
31+
32+
#define _CFBundleFHSDirectoryCLiteral_libexec "libexec"
33+
34+
#define _CFBundleFHSDirectoriesInExecutableSearchOrder \
35+
_CFBundleFHSDirectory_bin, \
36+
_CFBundleFHSDirectory_sbin, \
37+
_CFBundleFHSDirectory_libWithArchSuffix, \
38+
_CFBundleFHSDirectory_lib
39+
40+
#endif // CFBUNDLE_ALLOW_FHS_BUNDLES
41+
1842
// This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their
1943
// original locations on disk, so checking whether a binary's path exists is no longer sufficient.
2044
// For performance reasons, we only call dlopen_preflight() after we've verified that the binary
@@ -38,7 +62,22 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFURLRef urlPath, CFStringRef exeN
3862
CFURLRef executableURL = NULL;
3963
if (!urlPath || !exeName) return NULL;
4064

41-
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
65+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
66+
if (!executableURL) {
67+
executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLPOSIXPathStyle, false, urlPath);
68+
if (!_binaryLoadable(executableURL)) {
69+
CFRelease(executableURL);
70+
71+
CFStringRef sharedLibraryName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@%@"), _CFBundleFHSSharedLibraryFilenamePrefix, exeName, _CFBundleFHSSharedLibraryFilenameSuffix);
72+
73+
executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, sharedLibraryName, kCFURLPOSIXPathStyle, false, urlPath);
74+
if (!_binaryLoadable(executableURL)) {
75+
CFRelease(executableURL);
76+
executableURL = NULL;
77+
}
78+
}
79+
}
80+
#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI
4281
const uint8_t *image_suffix = (uint8_t *)__CFgetenvIfNotRestricted("DYLD_IMAGE_SUFFIX");
4382

4483
if (image_suffix) {
@@ -152,19 +191,60 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURL
152191
#else
153192
Boolean doExecSearch = true;
154193
#endif
194+
195+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
196+
if (lookupMainExe && bundle && bundle->_isFHSInstalledBundle) {
197+
// For a FHS installed bundle, the URL points to share/Bundle.resources, and the binary is in:
198+
199+
CFURLRef prefix = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url);
200+
201+
CFStringRef directories[] = { _CFBundleFHSDirectoriesInExecutableSearchOrder };
202+
size_t directoriesCount = sizeof(directories) / sizeof(directories[0]);
203+
204+
for (size_t i = 0; i < directoriesCount; i++) {
205+
CFURLRef where = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, prefix, directories[i], true);
206+
executableURL = _CFBundleCopyExecutableURLRaw(where, executableName);
207+
CFRelease(where);
208+
209+
if (executableURL) {
210+
foundIt = true;
211+
break;
212+
}
213+
}
214+
215+
CFRelease(prefix);
216+
}
217+
#endif // CFBUNDLE_ALLOW_FHS_BUNDLES
218+
155219
// Now, look for the executable inside the bundle.
156-
if (doExecSearch && 0 != version) {
220+
if (!foundIt && doExecSearch && 0 != version) {
157221
CFURLRef exeDirURL = NULL;
158222

223+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
224+
if (bundle && bundle->_isFHSInstalledBundle) {
225+
CFURLRef withoutExtension = CFURLCreateCopyDeletingPathExtension(kCFAllocatorSystemDefault, url);
226+
CFStringRef lastPathComponent = CFURLCopyLastPathComponent(withoutExtension);
227+
228+
CFURLRef libexec = CFURLCreateWithString(kCFAllocatorSystemDefault, CFSTR("../../" _CFBundleFHSDirectoryCLiteral_libexec), url);
229+
230+
CFStringRef exeDirName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), lastPathComponent, _CFBundleFHSExecutablesDirectorySuffix);
231+
exeDirURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, libexec, exeDirName, true);
232+
233+
CFRelease(withoutExtension);
234+
CFRelease(lastPathComponent);
235+
CFRelease(libexec);
236+
CFRelease(exeDirName);
237+
} else
238+
#endif // CFBUNDLE_ALLOW_FHS_BUNDLES
159239
if (1 == version) {
160240
exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase1, url);
161241
} else if (2 == version) {
162242
exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase2, url);
163243
} else {
164-
#if DEPLOYMENT_TARGET_WINDOWS
165-
// On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
244+
#if DEPLOYMENT_TARGET_WINDOWS || CFBUNDLE_ALLOW_FHS_BUNDLES
245+
// On Windows, Linyx if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory
166246
CFStringRef extension = CFURLCopyPathExtension(url);
167-
if (extension && CFEqual(extension, _CFBundleWindowsResourceDirectoryExtension)) {
247+
if (extension && CFEqual(extension, _CFBundleSiblingResourceDirectoryExtension)) {
168248
exeDirURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url);
169249
} else {
170250
exeDirURL = (CFURLRef)CFRetain(url);
@@ -232,15 +312,15 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) {
232312
#if DEPLOYMENT_TARGET_WINDOWS
233313
// Is this a .dll or .exe?
234314
if (buffLen >= 5 && (_wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".exe", 4) == 0)) {
235-
CFIndex extensionLength = CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension);
315+
CFIndex extensionLength = CFStringGetLength(_CFBundleSiblingResourceDirectoryExtension);
236316
buffLen -= 4;
237317
// If this is an _debug, we should strip that before looking for the bundle
238318
if (buffLen >= 7 && (_wcsnicmp((wchar_t *)&buff[buffLen-6], L"_debug", 6) == 0)) buffLen -= 6;
239319

240320
if (buffLen + 1 + extensionLength < CFMaxPathSize) {
241321
buff[buffLen] = '.';
242322
buffLen ++;
243-
CFStringGetCharacters(_CFBundleWindowsResourceDirectoryExtension, CFRangeMake(0, extensionLength), buff + buffLen);
323+
CFStringGetCharacters(_CFBundleSiblingResourceDirectoryExtension, CFRangeMake(0, extensionLength), buff + buffLen);
244324
buffLen += extensionLength;
245325
outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull);
246326
url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true);

CoreFoundation/PlugIn.subproj/CFBundle_Internal.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ CF_EXTERN_C_BEGIN
3030
#define PLATFORM_PATH_STYLE kCFURLPOSIXPathStyle
3131
#endif
3232

33+
// For development use only:
34+
#define _CFBUNDLE_ALLOW_FHS_BUNDLES_ON_ALL_TARGETS 0
35+
36+
#define CFBUNDLE_ALLOW_FHS_BUNDLES (_CFBUNDLE_ALLOW_FHS_BUNDLES_ON_ALL_TARGETS || !(DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS))
37+
38+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
39+
40+
#if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD || _CFBUNDLE_ALLOW_FHS_BUNDLES_ON_ALL_TARGETS
41+
#define _CFBundleFHSSharedLibraryFilenamePrefix CFSTR("lib")
42+
#define _CFBundleFHSSharedLibraryFilenameSuffix CFSTR(".so")
43+
#else // a non-covered DEPLOYMENT_TARGET…
44+
#error Disable FHS bundles or specify shared library prefixes and suffixes for this platform.
45+
#endif // DEPLOYMENT_TARGET_…
46+
47+
#endif // CFBUNDLE_ALLOW_FHS_BUNDLES
48+
3349
#define CFBundleExecutableNotFoundError 4
3450
#define CFBundleExecutableNotLoadableError 3584
3551
#define CFBundleExecutableArchitectureMismatchError 3585
@@ -62,6 +78,10 @@ struct __CFBundle {
6278

6379
CFURLRef _url;
6480

81+
#if CFBUNDLE_ALLOW_FHS_BUNDLES
82+
Boolean _isFHSInstalledBundle;
83+
#endif
84+
6585
CFDictionaryRef _infoDict;
6686
CFDictionaryRef _localInfoDict;
6787
CFArrayRef _searchLanguages;
@@ -348,7 +368,7 @@ CF_PRIVATE CFStringRef _CFBundleGetPlatformNameSuffix(void);
348368

349369
#define _CFBundleLocalizedResourceForkFileName CFSTR("Localized")
350370

351-
#define _CFBundleWindowsResourceDirectoryExtension CFSTR("resources")
371+
#define _CFBundleSiblingResourceDirectoryExtension CFSTR("resources")
352372

353373
#define _CFBundleMacOSXInfoPlistPlatformName_OLD CFSTR("macos")
354374
#define _CFBundleWindowsInfoPlistPlatformName_OLD CFSTR("win32")

0 commit comments

Comments
 (0)