CMake Build Mac App
Asked Answered
J

1

2

Our company uses CMake currently to build our executables for Windows. I'm working on making our application work on Mac. So far the application builds fine on the Mac. However, when I try to open the Executable that CMake creates for the Mac, I get the following error in a terminal window:

Last login: Tue Apr 16 14:34:58 on ttys001
Locals-MacBook-Pro:~ auser$ /Users/auser/Documents/Projects/CodeMonkey/bin/CmDeveloperKit ; exit;
dyld: Library not loaded: libAbcSupport.dylib
  Referenced from: /Users/auser/Documents/Projects/CodeMonkey/bin/CmDeveloperKit
  Reason: image not found
Trace/BPT trap: 5
logout

[Process completed]

I'm thinking that the CMakeLists.txt for the project might not be setup correctly to build the executable for the Mac. I've included it below:

# Includes the common stuff for CodeMonkey
include(CmConfig)

# Set the file description
set(CMDEVELOPERKIT_FILE_DESCRIPTION "CodeMonkey Application")

# Configures this CodeMonkey module
CmModuleConfig(CmDeveloperKit FIND CodeMonkey CodeMonkeyGui)

# Get source files for CodeMonkeyGui
set(PROJECT_SOURCES ${PROJECT_SOURCES} Main.cpp)
# Only add resource files on Windows
if(WIN32)
  # Get header files for CodeMonkeyGui
  set(PROJECT_HEADERS ${PROJECT_HEADERS} CmIcon.h)
  # Get source files for CodeMonkeyGui
  set(PROJECT_RESOURCES ${PROJECT_RESOURCES} CmIcon.rc)
endif(WIN32)

# Add additional include directories
include_directories(${CODEMONKEY_INCLUDE_DIR} ${CODEMONKEYGUI_INCLUDE_DIR} ${ABC_INCLUDE_DIR})
# Add additional link directories
link_directories("${ABC_LIBRARY_DIR}")

# Creates the executable
if(WIN32)
  add_executable(${PROJECT_NAME} WIN32 ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${PROJECT_RESOURCES})
  # Sets entry point to main
  set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/ENTRY:\"mainCRTStartup\"")
else()
  add_executable(${PROJECT_NAME} ${PROJECT_SOURCES} ${PROJECT_HEADERS} ${PROJECT_RESOURCES})
endif(WIN32)

# Add the d in debug
set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX d)

# Links to the other required libs
target_link_libraries(${PROJECT_NAME} ${CODEMONKEY_LIBRARY} ${CODEMONKEYGUI_LIBRARY} 
                      ${ABC_ARASUPPORT_LIBRARY} ${ABC_ARAGUI_LIBRARY})
# Sets the appropriate dependencies
add_dependencies(${PROJECT_NAME} ${CODEMONKEY_NAME} ${CODEMONKEYGUI_NAME})

# Configure the install procedures
CmModuleInstall()

Could someone please let me know what I'm missing or have wrong in the above file? If this file is not the issue can you point me in the right direction for a fix?

Janes answered 16/4, 2013 at 19:53 Comment(2)
Did you add a path of the directory containing libAbcSupport.dylib to DYLD_LIBRARY_PATH environment variable before trying to execute the application?Paramagnetism
@Haroogan Wow, I'll have to be honest and say that I didn't think that would work at first. It seems to have fixed the issue I was having though. Can you post this as an answer and explain more thoroughly what this does? Also, is there anyway to include the libAbcSupport.dylib within the Mac's App so I don't need to modify the environment variables to get the App to run? (reposting comment so you'll get a notification and because I'm past the time limit for editing it)Janes
P
4

You should add a path of the directory containing libAbcSupport.dylib to the DYLD_LIBRARY_PATH environment variable before starting the application.

For the reference, here is the dyld(1) man-page of OS X Manual. Extract:

DYLD_LIBRARY_PATH

This is a colon separated list of directories that contain libraries. The dynamic linker searches these directories before it searches the default locations for libraries. It allows you to test new versions of existing libraries.

For each library that a program uses, the dynamic linker looks for it in each directory in DYLD_LIBRARY_PATH in turn. If it still can't find the library, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALLBACK_LIBRARY_PATH in turn.

If you want this to be out-of-the-box, i.e. without needing to set this variable manually, then, for example, you should simply add proper installation process into CMakeLists. By default, DYLD_LIBRARY_PATH probably contains some directories, the system ones, and the user ones. Simply check it by:

echo $DYLD_LIBRARY_PATH

and consult the documentation on which directory is preferable (or sort of conventional) to deploy libraries for 3rd party applications on Mac OS X. Then all you'd have to do is to program CMakeLists so that on running make install it deploys libAbcSupport.dylib into such directory.

NOTE: You don't experience this problem on Windows because while Windows searches for the PATH environment variable to find DLLs too, it also searches in the current directory of the application (which is not the case for both Mac OS X and Linux). In other words, on Windows you most likely deploy AbcSupport.dll in the same directory as your application, and therefore don't have to worry about this.

NOTE: Linux is similar to Mac OS X in this regard. So if you ever have to port your application to Linux too, don't forget that you'll need LD_LIBRARY_PATH there. Here is LD.SO(8) man-page of Linux Programmer's Manual, and a relevant extract:

The LD_LIBRARY_PATH environment variable contains a colon-separated list of directories that are searched by the dynamic linker when looking for a shared library to load.

The directories are searched in the order they are mentioned in.

If not specified, the linker uses the default, which is /lib:/usr/lib:/usr/local/lib.

Paramagnetism answered 17/4, 2013 at 15:5 Comment(5)
This process produces a Linux style application layout on a Mac and relies on the Linux practice of setting the library path before executing the binary. It is wrong for a Mac application.Horologist
@Khouri, what are you talking about? What is a Linux style application layout? Please, be more specific. DYLD_ environment variables are defined by Mac OS X specifications of DYLD. Since author does not have proper installation procedure defined in CMake (which would allow to avoid DYLD_ environment variable dance), the above solution provides a possibility to run the built executable regardless.Paramagnetism
I'm talking about a self-contained application bundle using @rpath to find the libraries within the bundle. Linux style means your application is actually a shell script in /opt that sets LD_LIBRARY_PATH and then executes the real binary. If you're happy with that, that's ok. The general Mac population considers it abnormal.Horologist
I'm not happy with that and it's the first time I hear about such a crappy approach to deliver one's application, and I would definitely never recommend that. I always supply proper installation procedures to my CMake build systems, which take care of both, rpath modifications for binary artifacts in build tree (so that they are directly runnable) and proper deployment paths (depending on target OS) for various artifacts, e.g. /usr/lib for shared objects or /usr/bin for executables and etc. The above question does not ask about deployment and installation best practices for Mac OS X.Paramagnetism
A Mac application should not pollute /usr but keep all of that within it's bundle. On Linux and Windows, I would similarly keep all dependent libraries within a single folder. It's a little different if you are publishing a package on Linux. CMake's answer, even for the build tree, is your CMakeLists.txt writes a post build CMake script that does include(BundleUtilities) and calls fixup_bundle() that will walk the libraries to find runtime dependencies and then copy them all to the executable path. This works for Linux, Mac and Windows.Horologist

© 2022 - 2024 — McMap. All rights reserved.