On 2014-08-02, at 05:04 AM, Adam Strzelecki <[email protected]> wrote:
>> Please don't exaggerate the performance implications of copying a few
>> frameworks on the first build (…)
>
> This can be done, but discussion is going off-topic.
>
> Let us try first to move Qt frameworks to use @rpath & remove some
> unnecessary operations while keeping current workflow with minimal changes to
> the code. Therefore I hereby propose to (1) keep rpath to Qt SDK in built app
> executable, (2) not copy anything on build, (3) make macdeploy modify ONLY
> executable removing absolute rpath (instead fixing frameworks), and (4) just
> copy needed frameworks and (5) optionally sign whole bundle.
>
> This will not require any wrappers, environment variables or changes in Qt
> Creator to run your app. Only Qmake and macdeploy need to be changed.
>
> Frankly I don't see anything wrong with keeping full path to SDK in
> executable when it isn't yet completely bundled. And the initial intention
> was to NOT touch Qt SDK modules once they are built.
>
> Once this is done & working we can follow this discussion and think what can
> be done next.
>
> --
> Adam
This isn't off topic at all. @rpath, copying frameworks, DYLD_ environment
variables are all inseparably linked and very much part of the same discussion
and overall issue. Your proposal to simply add @rpath and do nothing else has
no benefits. What problem does it solve, other than deleting a bit of code from
macdeployqt that currently works and will continue to work without maintenance?
None. There is no point in doing it unless we go all the way and make the Qt
SDK completely relocatable.
I understand you want to start by completing one objective at a time, but keep
in mind each of these objectives is part of a greater overall goal. Alone, they
are pointless.
>> Actually you CAN add Info.plist to bundle-less apps using the linker
>> arguments: `-sectcreate __TEXT __info_plist Info.plist` which will embed it
>> in the binary. All OS X APIs handle this transparently. Though,
>> LSEnvironment is not a good solution for the problem we are trying to solve
>> here.
>
> I was expecting that ;) But wasn't your intention to not modify binary once
> it has been built and not hardcode any paths into it?
Yes, which is why I said LSEnvironment is not a good solution.
>> Why would you do any of these things?
>
> Because you dislike adding absolute rpath to Qt SDK in built binary during
> dev process.
All of those things involve hardcoding absolute paths *somewhere*. There should
be no absolute paths *anywhere* except environment variables that are
automatically set per-session.
>> "Inject"? DYLD_LIBRARY_PATH is an environment variable. You simply set it in
>> the process's environment before spawning.
>
> It is not so simple, first of all as you shown it works only from console,
> but if you launch it via GUI you need this variable to be set in launchd. As
> ~/.launchd.conf doesn't work anymore since Lion only permanent solution is to
> use /etc/launchd-user.conf which require admin to create/modify.
>
> Secondly DYLD_LIBRARY_PATH has strong security implications as the path is
> searched BEFORE default locations. So it does in fact let you inject/replace
> libraries. This is the reason dyld disables that for any process running
> under root account.
>
> man dyld
>
> DYLD_LIBRARY_PATH
>
> The dynamic linker searches these directories BEFORE it searches the
> default locations for libraries.
>
> What might be considered there is DYLD_FALLBACK_FRAMEWORK_PATH.
This is another excuse - there are no real security implications in practice.
If you're even thinking about this, your machine has already been compromised
and you no longer own it. Remember that this is a development time concern,
too, and has nothing to do with a production environment.
The security conscious Apple Inc. doesn't seem to think it's a big problem
either, because Xcode sets it during development (see below).
I'm curious in what realistic scenario you think this is a real problem.
>
>> In a terminal session, simply:
>>
>> $ export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/path/to/Qt/Frameworks
>> $ open /apps/MyApp.app
>>
>> In Creator, just click run and this will be handled automatically. In qbs
>> just type `qbs run -p foo` and this will be handled automatically.
>
> This won't work for apps launched directly via Finder/Dock.
Like I said, that doesn't matter. It didn't work in Qt 4 and the fact that it
works in Qt 5 is a mere side effect. No one will notice.
Most people build Qt apps on OS X using some IDE, most likely Qt Creator. Are
you seriously telling me you click build, go find the build directory, and
launch the app in Finder? That's ridiculous. You click the run button. If
you're willing to go through all the former effort you can easily export
DYLD_LIBRARY_PATH at the beginning of your terminal session and type `open
MyApp.app`. Note that the open command uses launch services which is the same
as double clicking the bundle in Finder.
Furthermore, if you simply copy frameworks into the bundle at build time like
every other native OS X app on the planet, this becomes a non-issue and you
don't even need DYLD_LIBRARY_PATH. With my QMAKE_EMBEDDED_FRAMEWORKS
suggestion, too, there would be a choice between the two, and be closer to
native tools behaviour at the same time.
>> ANY solution that involves placing absolute paths in ANY file inside the
>> MyApp.app/ directory tree is a wrong solution.
>
> You are wrong there. All system libs are referenced with their absolute paths.
Those are system libraries that are part of the operating system, present on
every OS X installation in the world and not designed to be relocatable. Qt is
not a system library and should be relocatable. Anything residing in /System
has no bearing on this discussion.
> Moreover the Qt's lib/ absolute path will be there only during development,
> in deployed binary absolute path will be removed via install_name_tool
> -delete_rpath.
This still breaks the rule of absolute paths appearing somewhere. We do not
want absolute paths anywhere during development except in per-session
environment variables.
>> Note that Qt Creator already does the logical equivalent of what I described
>> on Windows; the Qt libraries path is added to the PATH when the process is
>> launched. Launching directly in Explorer doesn't work, and launching
>> directly from Finder doesn't need to work either.
>
> Currently it DOES WORK when launching via Finder, because it does hardcode
> absolute path, so I don't see any reason it should stop working. Also it does
> work like that on Linux too.
Linux is not OS X (also did you forget about $ORIGIN?). And if we're going to
compare to other operating systems, currently it DOESN'T work on Windows. Never
seen a complaint about it. And that is not a problem because in 2014 people use
IDEs and click the run button which configures search paths for you. This is
why we have tools.
>> This is closer to how the native tools do things anyways.
>
> Which tools? AFAIK Xcode doesn't copy external frameworks into app bundle by
> default.
Yes it does. It has much specific functionality and behaviours for doing this
and this technique is encouraged by Apple and used by pretty much every
Xcode-using project on the planet. And the copying happens at development time,
for both debug and release. No one postpones this process to a release-time
packaging step like macdeployqt.
Examples of how Xcode facilitates this:
(1) Embedded binaries chooser on the Info tab of a target configuration
(2) Copy phase with an explicit selection for Frameworks on the Build Phases
tab of a target configuration
(3) Default prompt to embed a framework in an application target when creating
a new framework
(4) DYLIB_INSTALL_NAME_BASE set to @rpath by default when creating a new
framework
(5) OS X: LD_RUNPATH_SEARCH_PATHS set to @executable_path/../Frameworks for
apps and [@executable_path/../Frameworks, @loader_path/Frameworks] for
frameworks when creating a new target
(6) iOS: LD_RUNPATH_SEARCH_PATHS set to @executable_path/Frameworks for apps
and [@executable_path/Frameworks, @loader_path/Frameworks] for frameworks when
creating a new target
(7)
https://developer.apple.com/library/mac/documentation/macosx/conceptual/BPFrameworks/Tasks/CreatingFrameworks.html
(some parts are outdated as DYLD_LIBRARY_PATH is now set automatically, but
the rest of the documentation pretty much instructs users to do exactly what I
am suggesting)
This is not a novel idea I just came up with. This has been the standard
workflow on OS X for over a decade.
>> Symlinks make no sense. Just copy the full frameworks, there is no
>> disadvantage to this. This is the standard workflow for development on Apple
>> platforms anyways and has been since NeXTSTEP.
>
> See above.
>
>> I'm sure someone will bring up "performance!!1" but that is a poor argument;
>
> This is going off-topic. It was about to bring @rpath to Qt frameworks not
> rework entire workflow.
The whole point of @rpath is to enable this improvement in workflow. By itself
there is no point in adding it other than *slightly* simplifying some
macdeployqt code.
>>> I don't think you should add these by default since Qt doesn't need them,
>>> so unlikely your app need them. If you use some 2rd party library you are
>>> free to extend QMAKE_RPATH list yourself.
>>
>> It might need them. Depends if we change macdeployqt to place a dylibs
>> (non-frameworks) build of Qt libraries inside Libraries instead of
>> Frameworks. Not a major part of the discussion anyways, just an idea.
>
> I don't see point of handling some custom scenarios that anyway are not what
> is expected (standard) app bundle.
Fair enough, let's focus on the task at hand.
>> Let's use standard solutions instead of strange contraptions. Standard
>> solutions involve @rpath along with DYLD_LIBRARY_PATH, copying frameworks at
>> build time, or both (preferably both).
>
> I am sorry, but you are wrong. DYLD_LIBRARY_PATH is nowhere used in Xcode and
> DYLD_ variables exist for dyld debug purposes.
Apologies for parroting, but... you are in fact wrong. I've JUST tested this
and Xcode does in fact set many environment variables when running an
application. I've added NSLog(@"%@", [[NSProcessInfo processInfo]
environment]); in my application delegate. Here's a subset of the output:
2014-08-02 17:12:48.775 Silverlock[24258:303] {
"DYLD_FRAMEWORK_PATH" =
"/Users/jakepetroules/Library/Developer/Xcode/DerivedData/Silverlock-dozbffgewlkgfucjgrjfbjopeyhq/Build/Products/DebugAppStore";
"DYLD_LIBRARY_PATH" =
"/Users/jakepetroules/Library/Developer/Xcode/DerivedData/Silverlock-dozbffgewlkgfucjgrjfbjopeyhq/Build/Products/DebugAppStore";
PATH =
"/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin";
PWD =
"/Users/jakepetroules/Library/Developer/Xcode/DerivedData/Silverlock-dozbffgewlkgfucjgrjfbjopeyhq/Build/Products/DebugAppStore";
"__XCODE_BUILT_PRODUCTS_DIR_PATHS" =
"/Users/jakepetroules/Library/Developer/Xcode/DerivedData/Silverlock-dozbffgewlkgfucjgrjfbjopeyhq/Build/Products/DebugAppStore";
"__XPC_DYLD_FRAMEWORK_PATH" =
"/Users/jakepetroules/Library/Developer/Xcode/DerivedData/Silverlock-dozbffgewlkgfucjgrjfbjopeyhq/Build/Products/DebugAppStore";
"__XPC_DYLD_LIBRARY_PATH" =
"/Users/jakepetroules/Library/Developer/Xcode/DerivedData/Silverlock-dozbffgewlkgfucjgrjfbjopeyhq/Build/Products/DebugAppStore";
}
I work with Xcode on a daily basis building native Cocoa apps. I can assure you
I'm well aware of the standards and conventions in use by Apple and their
development tools. Bringing Qt in line with standard expectations for OS X and
iOS development is important to maintain and grow its competitive edge. Tools
like macdeployqt are an extremely foreign concept on OS X and iOS and are
confusing to newcomers and annoying for veterans. No other SDK that I know if
has anything of the sort, nor uses absolute sonames.
No need to mention MacPorts, Homebrew, etc., either, which probably use
absolute paths for most builds. Package management systems in general have a
whole set of conventions. For example, Fedora prohibits rpath usage in the
package management system. This is correct and justified. Installed packages in
a PMS are never relocated. Application bundles and SDKs on OS X *are*.
> Try to create simple framework and see what happens, checkout install name of
> built framework.
>
> $ otool -L
> /Users/ono/Library/Developer/Xcode/DerivedData/TestFramework-aduwyulqilsereeqgoizoxubgbdy/Build/Products/Debug/TestFramework.framework/TestFramework
>
> /Users/ono/Library/Developer/Xcode/DerivedData/TestFramework-aduwyulqilsereeqgoizoxubgbdy/Build/Products/Debug/TestFramework.framework/TestFramework:
> /Library/Frameworks/TestFramework.framework/Versions/A/TestFramework
> (compatibility version 1.0.0, current version 1.0.0)
> /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
> (compatibility version 1.0.0, current version 20.0.0)
> /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
> (compatibility version 300.0.0, current version 1056.13.0)
> /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version
> 228.0.0)
> /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
> version 1197.1.1)
>
>
>
> Now create a Cocoa app and framework from the framework project as see how
> the framework is referred and check if you can find the framework inside
> bundle.
>
> $ otool -L
> /Users/ono/Library/Developer/Xcode/DerivedData/SampleApp-fwmalbohyjlyqgdhjvnicwjqqmfr/Build/Products/Debug/SampleApp.app/Contents/MacOS/SampleApp
>
> /Users/ono/Library/Developer/Xcode/DerivedData/SampleApp-fwmalbohyjlyqgdhjvnicwjqqmfr/Build/Products/Debug/SampleApp.app/Contents/MacOS/SampleApp:
> /Library/Frameworks/TestFramework.framework/Versions/A/TestFramework
> (compatibility version 1.0.0, current version 1.0.0)
> /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa
> (compatibility version 1.0.0, current version 20.0.0)
> /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation
> (compatibility version 300.0.0, current version 1056.13.0)
> /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version
> 228.0.0)
> /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current
> version 1197.1.1)
> /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit
> (compatibility version 45.0.0, current version 1265.19.0)
Point being? The system default DYLIB_INSTALL_NAME_BASE for frameworks in the
Xcode build system happens to be /Library/Frameworks. For new projects it
should be set to @rpath (and the IDE does this when creating a new target).
Nothing to see here.
> --
> Adam
So, let's certainly start with adding @rpath to Qt libraries. But let's not
stop there, either.
--
Jake Petroules - jake.petroules at petroules.com
Chief Technology Officer - Petroules Corporation_______________________________________________
Development mailing list
[email protected]
http://lists.qt-project.org/mailman/listinfo/development