Skip to content

Conversation

@pvieito
Copy link
Contributor

@pvieito pvieito commented May 31, 2018

  • This enables finding Freestanding bundles directory from the executable path as specified on the FHS Bundles doc.
  • Unifies Windows implementation with other platforms.

- This enables to find freestanding bundles directories.
- Unifies Windows and other platforms approach.
- Initial implementation (there are some leaks).
return executableURL;
}

static CFStringRef _CFStringRemovePrefixSuffix(CFStringRef str, CFStringRef prefix, CFStringRef suffix) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to have a Create in the name.

Copy link
Contributor Author

@pvieito pvieito May 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe _CFBundleCopyNameByRemovingExcutablePlatformPrefixSuffix?

kCFCompareAnchored|kCFCompareBackwards);

CFStringReplace(mutableString, suffixRange, CFSTR(""));
return mutableString;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this function be calculating the range then just calling CFStringCreateWithSubstring instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's a lot better, thanks!

CFIndex extensionLength = CFStringGetLength(_CFBundleSiblingResourceDirectoryExtension);
buffLen -= 4;
// If this is an _debug, we should strip that before looking for the bundle
if (buffLen >= 7 && (_wcsnicmp((wchar_t *)&buff[buffLen-6], L"_debug", 6) == 0)) buffLen -= 6;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like support for _debug may have been lost in this code and above?

Copy link
Contributor Author

@pvieito pvieito May 31, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is this still required by Core Foundation on Windows?


// Otherwise, use the executable name as bundle name (CF).
if (!bundleName) {
bundleName = executableName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a CFRetain(executableName) here and CFRelease(bundleName) below to avoid leaking.

}

// Find the sibling `.resources` directory (CF.resources).
CFURLRef parentDirectory = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, executableURL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leak

#if FREESTANDING_BUNDLES
if (!url) {
CFURLRef executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false);
CFStringRef executableName = CFURLCopyLastPathComponent(executableURL);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaked

if (buffLen >= 7 && (_wcsnicmp((wchar_t *)&buff[buffLen-6], L"_debug", 6) == 0)) buffLen -= 6;
#if FREESTANDING_BUNDLES
if (!url) {
CFURLRef executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaked


// Find the sibling `.resources` directory (CF.resources).
CFURLRef parentDirectory = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, executableURL);
CFStringRef siblingResourceDirectoryName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@.%@"), bundleName, _CFBundleSiblingResourceDirectoryExtension);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More leaks... these all should be taken care of.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, I am aware, work in progress :)

#endif

// Freestanding bundles are supported on all platforms.
#if TRUE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be enabled on Darwin.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be useful for things like CLI tools that may require some resources without being in an app bundle. In any case I will disable in Darwin for now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLI that require resources have their own mechanism on Darwin. Freestanding bundles are for FHS OSes and Windows only.

@parkera
Copy link
Contributor

parkera commented May 31, 2018

What's the plan here? Mainly a refactoring?

@pvieito
Copy link
Contributor Author

pvieito commented May 31, 2018

Yes, a bit of cleaning, unifying the old freestanding Windows bundles with the new cross-platform implementation and allow reverse bundle lookup (finding the bundle resources folder from the executable location) which was not available.

This will enable using Bundle.main.url(forResource:withExtension:) to find resources on a ExecutableName.resources directory sibling to the executable on Linux.

@millenomi
Copy link
Contributor

@pvieito Are you sure the failure for that mode wasn't #1568 ? Can you articulate what was the issue here?

@pvieito
Copy link
Contributor Author

pvieito commented May 31, 2018

@millenomi No, you implemented the logic to search the Bundle executable from the Bundle directory for Freestanding and FHS bundles (in _CFBundleCopyExecutableURLInDirectory2). This PR implements the reverse logic for Freestanding ones, which allows to find the Bundle directory from the executable path (in _CFBundleCopyBundleURLForExecutablePath).

This is required for things like Bundle.main.resourcePath resulting in the sibling ExecutableName.resources directory as specified on the FHS Bundles doc.

Of course the #1568 fix is required, but this PR extends the implementation.

if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) {
CFStringRef bareExeName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6));
newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix);
newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), bareExeName, imageSuffix);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This, I suppose was a bug due a typo. Am I correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split fixes to the core from refactoring? The more that changes in a single PR, the more confusing differential diagnosis can be in the future.

@pvieito pvieito changed the title [WIP] Added support for Freestanding Bundles reverse lookup Added support for Freestanding Bundles reverse lookup May 31, 2018
@pvieito
Copy link
Contributor Author

pvieito commented May 31, 2018

@millenomi Also, the reverse lookup for FHS Installed bundles remains undone, so you cannot retrieve resources from a Executable installed in /bin/ExecutableName from /share/ExecutableName.resources with Bundle.main.url(forResource:withExtension:). For now, the bundle directory is “detected” at /bin/.

Copy link
Contributor

@millenomi millenomi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have a more focused patch for each issue than a single redo that tries to address multiple things at once.

#endif

#if !DEPLOYMENT_RUNTIME_OBJC && !DEPLOYMENT_TARGET_WINDOWS && !DEPLOYMENT_TARGET_ANDROID
#if FHS_BUNDLES
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it looks cleaner, the use of explicit platforms was intentional — we need to see what code is called on what paths, and obscuring those platforms makes us no favor. It's long but useful.

(In addition, as a note for the future since we should remove this: we do not introduce macros without prefixes. If we wanted to keep this, it should've been _CF_… since it's internal.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have changed it but added a comment (/* FHS_BUNDLES */ or /* FREESTANDING_BUNDLES */) in each appearance so all cases are easily searchable. They were already out of sync (some of the FHS_BUNDLES cases had not the DEPLOYMENT_TARGET_ANDROID and some had them).

if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) {
CFStringRef bareExeName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6));
newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix);
newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), bareExeName, imageSuffix);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we split fixes to the core from refactoring? The more that changes in a single PR, the more confusing differential diagnosis can be in the future.

newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, imageSuffix);
}
executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, newExeName, kCFURLPOSIXPathStyle, false, urlPath);
executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, newExeName, PLATFORM_PATH_STYLE, false, urlPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed, because this region is Darwin only. Using it can confuse the waters a bunch (why are we using a cross-platform macro here? What platforms does this code run on?)

CFRelease(newExeName);
CFRelease(imageSuffix);
}
#endif
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these blocks are long-ish, it's probably a good idea to decorate the #endifs.

if (!executableURL) {
executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLPOSIXPathStyle, false, urlPath);
// Try finding the executable with input name.
executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, PLATFORM_PATH_STYLE, false, urlPath);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code would be executed on Windows.

if (_CFURLExists(siblingResourceDirectoryURL)) {
url = siblingResourceDirectoryURL;
}
else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit: same line as preceding }.

func test_bundleReverseBundleLookup() {
_withEachPlaygroundLayout { (playground) in
if playground.layout == .fhsInstalled {
// Pending to be implemented.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same TODO.


import CoreFoundation

#if DEPLOYMENT_RUNTIME_OBJC || os(Linux) || os(Android)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have consolidated these imports elsewhere. Isn't it working?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, unfortunately I need internal symbols that are not available with the @_exported import Foundation line in TestImports.swift. I also tried there to add @testable but it does not work.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A change that needs to be made after the last few updates to CI building: you need to guard use of @testable import like this:

#if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT
#if DEPLOYMENT…
@testable import 
// etc
#endif
#endif

Tests that make use of internal symbols must also be bracketed by #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Support for this to actually run those tests once bracketed is coming in the next attempt at #1597. Unfortunately, it has been temporarily reverted.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! So, after that change is merged we should start a new test for this PR as the current test won't test anything, I suppose 🤔

#endif

// FHS bundles are supported on the Swift and C runtimes, except on Windows.
// Freestanding bundles are not supported on Darwin.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above for the discussion about feature flags. (Short: no.)

#define FREESTANDING_BUNDLES 0
#endif

// FHS bundles are not supported on Darwin, Windows and Android.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorrect: they're supported on Darwin if we build with the Swift runtime. See earlier comment.

@pvieito
Copy link
Contributor Author

pvieito commented Jun 13, 2018

Can anyone start the test, please? Also, any feedback after the last changes?

@millenomi
Copy link
Contributor

@swift-ci please test

@millenomi
Copy link
Contributor

@swift-ci please test

@pvieito
Copy link
Contributor Author

pvieito commented Jun 20, 2018

@millenomi Are @testable imports already fixed?

@millenomi
Copy link
Contributor

millenomi commented Jun 20, 2018

@pvieito they aren't yet, but you can wrap code in a #if NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT block and it will be good for today. (You can test it locally before bracketing it with this #if with ninja test@testable import will work locally, just not on CI.)

@pvieito
Copy link
Contributor Author

pvieito commented Jun 20, 2018

@millenomi Ok, I already did it! Could you start a CI build/test to ensure the PR builds successfully, please?

@alblue
Copy link
Contributor

alblue commented Jun 22, 2018

@swift-ci please test

@pvieito
Copy link
Contributor Author

pvieito commented Aug 4, 2018

Could we merge this? I was waiting for #1600 to add NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT support but it seems it is not going to be merged any time soon.

@alblue
Copy link
Contributor

alblue commented Aug 7, 2018

@millenomi @parkera can you review the changes you requested and approve where appropriate?

@millenomi
Copy link
Contributor

@pvieito Sorry for the long wait; it's been an intense summer. Are you still interested in chaperoning this patch?

@pvieito
Copy link
Contributor Author

pvieito commented Oct 11, 2018

@millenomi Yes, I have merged the master changes and tested it locally.

@pvieito
Copy link
Contributor Author

pvieito commented Oct 11, 2018

@swift-ci please test

@millenomi
Copy link
Contributor

@swift-ci please test

@pvieito
Copy link
Contributor Author

pvieito commented Oct 12, 2018

@millenomi Any idea why the tests did not start?

@pvieito
Copy link
Contributor Author

pvieito commented Oct 12, 2018

@swift-ci please test

2 similar comments
@spevans
Copy link
Contributor

spevans commented Oct 12, 2018

@swift-ci please test

@pvieito
Copy link
Contributor Author

pvieito commented Oct 13, 2018

@swift-ci please test

@pvieito
Copy link
Contributor Author

pvieito commented Oct 13, 2018

The macOS test seems to have failed due to external problems

@spevans
Copy link
Contributor

spevans commented Oct 13, 2018

@swift-ci please test

@pvieito
Copy link
Contributor Author

pvieito commented Oct 14, 2018

@swift-ci please test // cc. @spevans Thanks!

@millenomi If the tests complete successfully the PR should be prepared for merging.

@spevans
Copy link
Contributor

spevans commented Oct 14, 2018

@swift-ci please test

@pvieito
Copy link
Contributor Author

pvieito commented Oct 14, 2018

The tests have succeeded (even though GitHub is not reporting them):

@pvieito
Copy link
Contributor Author

pvieito commented Oct 16, 2018

@millenomi Could you review and merge it (if ok)?

@pvieito
Copy link
Contributor Author

pvieito commented Apr 17, 2019

Closing this PR as it is superseded by #2093.

@pvieito pvieito closed this Apr 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants