If no additional directory in the install_name of a dynamic library, then which path does dyld search? - macos

Mac, for a compiled project (using QT 5.5.0), I directly run the executable file, the error:
libraw.10.dylib not loaded;
OK, I know the reason.
One solution is to use install_name_tool to change the install name of libraw.10.dylib and put it in somewhere, like in the article:
"Qt for OS X - Deployment"
But right now I don't want to do this way.
One reason is that I do not need to really deploy it; so I want to make it simpler by only copying the library "libraw.10.dylib" to the right place.
The second reason is that I am curious what the default path for an install name without additional directory.
But no matter where I put the file "libraw.10.dylib", the same error comes out.
I tried to look into the details in the man page of dyld,
I couldn't figure it out.
Maybe all path variables are empty (I tried several popular variables, such as DYLD_FALLBACK_FRAMEWORK_PATH, DYLD_FALLBACK_LIBRARY_PATH, etc; they are empty).
Then I put the library "libraw.10.dylib" on the root, parallel to the folder "Applications". Still the same error.
So what dyld is looking for when it encounters:
libraw.10.dylib

Related

Connecting dots from self-contained Java application to Mac OS installation

I am not a Mac owner and am putting myself through a crash course to get up to speed (e.g., reading "Switching to the Mac"), to give you an indication of my current level of understanding. The access I have to a physical Mac is limited, so I am trying to connect as many dots as possible before my next session with my friend's computer.
I have: a file folder containing all resources needed for a self-contained application written with Java (OpenJDK 11, JavaFX 11). The JLINK tool was successfully used to create this file folder, and it holds all necessary Java libraries as well as the code I wrote for the application. The executable resides in a subfolder: /bin. The program runs perfectly well on the Mac when the executable is run.
I want: something that is easy to download, install and run.
I'm unclear about what needs to be done to get this. The road map seems to have two main steps:
the file folder needs to be converted into something that responds as if it were an application (e.g., a Bundle? or an .app?)
the resulting folder-as-executable can be shipped via either .dmg or .pkg
For the second part, I've researched and found tools such as Packages or create-dmg. It seems to me these tools are pretty straightforward and shouldn't be too difficult to learn to use. (Just have to pick one or the other or something similar.)
For the first part, I'm on shaky conceptual ground. I've found info about Bundles, but no tutorials, walk-throughs or examples. It looks like a key step is understanding how to make a proper Info.plist file, but doing this properly looks tricky. Also, I'm not clear on how the resulting Bundle will become an .app file or if it needs to, or if there is another, more direct way to make my file folder be viewed by the OS as an application.
Some hand-holding or references to tutorials or even assurance that I am on the right track (if that is the case) would be much appreciated. Thanks!
The Java Deployment guide from Oracle relies heavily on ANT, but doesn't cover the case of a self-contained, customized JVM via JLINK well enough for me to decipher. So, I've taken the approach of trying to learn/understand the necessary steps using command-line commands.
While creating a Bundle is certainly an option, there is an easier way.
Step one is to make an .app manually. An answer to this question: "How to make a Mac OS X .app with a shell script?" goes over the basic steps. The Java file system that results from jlinking has a folder /bin in which there is a bash file that runs the program. This file should be moved to the outermost folder, and it should be named the desired name of the application. The bash file itself will have to be edited and "/bin" added to the address in last command so that the executable will be found. In addition, the folder itself will have to be renamed to be the same as the bash file, but with .app added as an extension.
The next thing I wanted to have was a custom icon. The question "Include icon in manually created app bundle" shows how to do this.
For the next step I made use of the program "Packages". I'm a bit confused about where I downloaded this from (there seem to be multiple sites), but here is a link to the manual. This tool allowed me to create a .pkg file that, when executed, installs my .app in the Applications folder. Then I compressing the .pkg file (to .zip) and made it available at a URL for downloading.
I've had a friend do a test download and install, and the program works!
This isn't meant to be a complete tutorial, and there are a few steps more that I want to figure out pertaining to sandboxing and sealing, but I believe this is a reasonable roadmap that can be used for simpler jlinked Java applications for Mac distribution.

Programmatically locate gswin32.exe

My program needs to locate an existing GhostScript install, and run gswin32.exe (or the 64-bit version if installed) with some command-line options to do a silent conversion of PS to PDF. How should I go about this? I see they add some registry settings under HKEY_LOCAL_MACHINE\SOFTWARE\GPL Ghostscript\9.07, but I only see a LIB path (which has several paths) and a DLL path, nothing for the EXE. I could work backwards from the DLL path, I guess, but not sure if that will be "future proof".
For the type of app GhostScript is, I would assume they would make this part very easy and obvious, since a lot of programs will be doing exactly this. With all of the free "print to PDF" drivers out there, you would think this info would be easy to find, and maybe it is, but I sure can't find it. Hopefully I'm just missing something, because I don't know where to search, or the right keywords to find it on Google.
I'm tempted to use "GSLite", but so far the only places I've found to download this doesn't have any info on how to download the GS source code for the build of GS they are using, and I think that violates the GS license (not making source code available), so for now I'm just thinking I'll have users install GS themselves, and just look for it -- instead of making it a sub-folder under my app or anything like that.
try ftype (which of course may give acrobat or something, but worth a shot)
maybe some windows expert can tell how to acess the alternate apps list you get by right clicking a ps file...
HKEY_LOCAL_MACHINE\SOFTWARE\Artifex\GPL Ghostscript\9.07
After doing a registry search for a few different keywords, I found the above key which contains a (default) string that points to the install directory. I then did a Google search on that registry key and found some links to the GhostScript source code that sets that value, so I think it is safe to use. I would post those links here, but none of them are good sources (one I had to use Google's "from cache" feature, and the other was just a random person posting a snip-it of GS code). I'm sure it is in the official source code download from their website, if anyone else needs to confirm this, possibly a file named nsisinst.nsi, an install script.

Win32 module loading from multiple directories

I have a program which stores plugins in multiple directories, like so:
root/
core/bin/
app.exe
core.dll
plugin.dll
support.dll
a/bin/
a.dll
a_support.dll
In this example, a.dll imports core.dll, support.dll, and a_support.dll (they are in that order in the import table). a_support.dll imports support.dll. I can change all but the support modules, those are redists of a third-party library.
My code calls LoadLibraryEx(name, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) to load each plugin. For core.dll and plugin.dll, this works fine.
When I try to load a.dll, it fails saying a_support.dll was not found. No errors about core.dll or support.dll, perhaps because they're already in memory.
My suspicion is that when a_support.dll is loaded, support.dll cannot be found, but this seems unusual as a.dll appears to import support.dll before a_support.dll.
Is this layout of modules even possible to use? Will the system be able to use the already-loaded support DLLs, or will it go searching for them and fail? Would there be a way to handle this through manifests? Is there a way to make this work, or will I have to relocate all modules into a single directory?
Edit: At Adrian McCarthy's suggestion, I ran the loading sequence with Process Monitor tracking, and it seems that when I call LoadLibrary("root/a/bin/a.dll", ...), it starts by searching the root directory, then system directories, then down through the path. For some reason, it never searches a/bin/, which it very much should.
I double-checked the paths, and noticed that my calls to load plugin.dll where using the wrong path (root, instead of root/core/bin). Either way, core.dll was loading correctly. After fixing that, I tried it again and this time a.dll does find a_support.dll and seems to load. However, that makes absolutely no sense, unless the loader is successfully using support.dll from... somewhere. The procmon log doesn't show it even attempting to load support.dll again, so I'm not entirely sure at this point if there actually is a problem (besides behavior from the loader that makes no sense).
I suggest using Process Monitor to see what's really happening. You'll see if it's looking in the right place, whether a_support.dll is opened but not loadable because something else is missing, etc.
Certainly one solution would be to place all DLLs in the same directory, the same directory as the .exe. If you can bring yourself to do that it would be the simplest approach for sure.
If not then you will have a bit more work on your hands. I guess you are expecting that the loader will search in the directory where the DLL lives. Sadly it doesn't. Instead the loader will look first in the executable file's directory, and then the rest of the DLL search order. This is why a_support.dll fails to load, because it is not in the same directory as the executable.
The fact that modules are already in memory is beside the point. The loader goes looking for the file. When it finds the file that it wants it then checks to see if it is already loaded. If so then it simply bumps the reference count to that module. Otherwise it loads it into the process.
You could switch to using LoadLibrary for all DLL loads and always being explicit about the path. That's probably inconvenient.
You could use side-by-side assemblies but that doesn't sound very compatible with a plugin architecture.
So I think the main remaining option is SetDllDirectory. Call this just before you load the plugin. You only need to add a/bin to the search path since the rest of the modules are in the executable directory and so will be found without trouble. Restore this setting to its default by calling SetDllDirectory again, passing NULL, once the plugin has loaded and resolved all of its imports.
If you have multiple sub-directories then use AddDllDirectory.
This is a rather confusing application.
Some questions then:
Which dll's does app.exe implicitly import?
core.dll is both implicitly loaded by a.dll AND as a plugin via LoadLibraryEx?
How was the call to LoadLibraryEx on /plugin.dll ever succeeding? If the path was FQ and did not point at an actual dll, LoadLibrary should have failed outright on that dll.
I can't tell if you're giving sample code or real code. You wrote:
LoadLibrary("root/a/bin/a.dll", ...)
If that's the real code, there are two problems here.
First, LoadLibrary doesn't do what you'd expect with a relative path. From MSDN:
To load a module from a relative path without searching any other
path, use GetFullPathName to get a nonrelative path and call
LoadLibrary with the nonrelative path. For more information on the DLL
search order, see Dynamic-Link Library Search Order.
Basically, you give it a full path and get that file, or you let it search for a name in all the "usual" locations. If you give it a relative path, it basically ignores that path, grabs the name, and looks in the usual locations.
If you really meant LoadLibraryEx, note that when you use LOAD_WITH_ALTERED_SEARCH_PATH you get "undefined behavior" if handed a relative path. Again quoting MSDN:
If this value is used and lpFileName specifies a relative path, the behavior is undefined.
Second, you have forward slashes instead of backslashes. Neither LoadLibrary nor LoadLibraryEx likes those.

How do I make my gem place a .dll in a folder in the system PATH upon installation?

... and remove it upon un-installation, of course.
The issue is that other programs being called from my gem need to be able to find a certain file in the system PATH - setting the PATH programatically doesn't work, as these programs are being called in a way that they get a fresh environment.
I tried including these .dll files as "executables" in the gemspec, but that only seems to get some symlink type files in the {ruby}/bin folder, which causes errors because the programs in question are expecting the actual .dll.
As it is, I just have a note in the README asking people to manually copy the .dll files to a folder in the PATH, but it seems like there should be a better way to do this.
Any help would be appreciated - thanks!
I guess the dll is a native lib required by a java class?
If so, you can just put it somewhere in the lib folder and call java.lang.System.load to load it before the java class is used. It doesn't have to be in system PATH this way.

IBPlugin and paths to framework

IBCocoaSimulator crashes when IB cannot find the framework, I assume that happens to you too. I can run IBCocoaSimulator without crash, when I manually copy my framework+ibplugin from the build dir into /Users/username/Library/Frameworks. I'm doing this with Finder, this is not optimal, but works.
I have searched for a smarter way and each solution (BWToolkit, BGHUDAppKit, KTUIKit) I have been looking at, does things in much different ways. One solution runs a sudo script that copies it to the system wide /Library/Frameworks. Another sets #loader_path and yet another uses #executable_path. I haven't had luck with any of them and because of the great differences it's hard to see the pattern.
I'm confused.
How do you config you IBPlugin, so that you can embed it in your app?
UPDATE 1:
Yay, solved it, after reading a blog post by dribin about how to use #rpath, I figured out how to get it working with my IBPlugins. So copy using Finder is no longer needed.
What I did was:
For MySmallFramework set Installation Directory to #rpath
For MySmallPlugin set Runpath Search Paths to #loader_path/../Frameworks
For MySmallApp set Runpath Search Paths to #loader_path/../Frameworks
Nice.
Might be obvious to most of you, but neoneye's solution as posted in his "Update 1" requires your plugin target to have a "copy framework files" build phase with the given framework assigned to.
(don't yet have enough points for direct commenting :( hence the answer post)
You can call this with external makefiles xcode project from ibplugin makefile like following example:
install_name_tool -change #loader_path/MyPluginName.framework/MyPluginName #loader_path/<absolute path or level to updirectory>/MyPluginName.framework/MyPluginName $(BINDIR)/MyPluginName.ibplugin/Contents/MacOS/MyPluginName

Resources