BundleUtilities: Work w/ non .app exes on Mac (#12034)
Also add a test of BundleUtilities including an exe, some shared libs, a plugin, and a framework-style lib. This test presently runs (and this functionality works) on Linux, Mac and Windows. For now, the framework-style lib is built as a plain old shared lib because there is another yet-unresolved issue with local frameworks without rpaths on the Mac.
This commit is contained in:
parent
ba6579f7a3
commit
7ac7b437b8
|
@ -53,9 +53,8 @@
|
||||||
#
|
#
|
||||||
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
|
# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>)
|
||||||
# Returns the nearest parent dir whose name ends with ".app" given the full
|
# Returns the nearest parent dir whose name ends with ".app" given the full
|
||||||
# path to an executable. If there is no such parent dir, then return a dir at
|
# path to an executable. If there is no such parent dir, then simply return
|
||||||
# the same level as the executable, named with the executable's base name and
|
# the dir containing the executable.
|
||||||
# ending with ".app"
|
|
||||||
#
|
#
|
||||||
# The returned directory may or may not exist.
|
# The returned directory may or may not exist.
|
||||||
#
|
#
|
||||||
|
@ -227,35 +226,35 @@ endfunction(get_bundle_main_executable)
|
||||||
function(get_dotapp_dir exe dotapp_dir_var)
|
function(get_dotapp_dir exe dotapp_dir_var)
|
||||||
set(s "${exe}")
|
set(s "${exe}")
|
||||||
|
|
||||||
set(has_dotapp_parent 0)
|
|
||||||
if(s MATCHES "^.*/.*\\.app/.*$")
|
if(s MATCHES "^.*/.*\\.app/.*$")
|
||||||
set(has_dotapp_parent 1)
|
# If there is a ".app" parent directory,
|
||||||
endif(s MATCHES "^.*/.*\\.app/.*$")
|
# ascend until we hit it:
|
||||||
|
# (typical of a Mac bundle executable)
|
||||||
set(done 0)
|
#
|
||||||
while(NOT ${done})
|
set(done 0)
|
||||||
get_filename_component(snamewe "${s}" NAME_WE)
|
while(NOT ${done})
|
||||||
get_filename_component(sname "${s}" NAME)
|
get_filename_component(snamewe "${s}" NAME_WE)
|
||||||
get_filename_component(sdir "${s}" PATH)
|
get_filename_component(sname "${s}" NAME)
|
||||||
if(has_dotapp_parent)
|
get_filename_component(sdir "${s}" PATH)
|
||||||
# If there is a ".app" parent directory,
|
|
||||||
# ascend until we hit it:
|
|
||||||
# (typical of a Mac bundle executable)
|
|
||||||
#
|
|
||||||
set(s "${sdir}")
|
set(s "${sdir}")
|
||||||
if(sname MATCHES "\\.app$")
|
if(sname MATCHES "\\.app$")
|
||||||
set(done 1)
|
set(done 1)
|
||||||
set(dotapp_dir "${sdir}/${sname}")
|
set(dotapp_dir "${sdir}/${sname}")
|
||||||
endif(sname MATCHES "\\.app$")
|
endif(sname MATCHES "\\.app$")
|
||||||
else(has_dotapp_parent)
|
endwhile(NOT ${done})
|
||||||
# Otherwise use a directory named the same
|
else(s MATCHES "^.*/.*\\.app/.*$")
|
||||||
# as the exe, but with a ".app" extension:
|
# Otherwise use a directory containing the exe
|
||||||
# (typical of a non-bundle executable on Mac, Windows or Linux)
|
# (typical of a non-bundle executable on Mac, Windows or Linux)
|
||||||
#
|
#
|
||||||
set(done 1)
|
is_file_executable("${s}" is_executable)
|
||||||
set(dotapp_dir "${sdir}/${snamewe}.app")
|
if(is_executable)
|
||||||
endif(has_dotapp_parent)
|
get_filename_component(sdir "${s}" PATH)
|
||||||
endwhile(NOT ${done})
|
set(dotapp_dir "${sdir}")
|
||||||
|
else(is_executable)
|
||||||
|
set(dotapp_dir "${s}")
|
||||||
|
endif(is_executable)
|
||||||
|
endif(s MATCHES "^.*/.*\\.app/.*$")
|
||||||
|
|
||||||
|
|
||||||
set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
|
set(${dotapp_dir_var} "${dotapp_dir}" PARENT_SCOPE)
|
||||||
endfunction(get_dotapp_dir)
|
endfunction(get_dotapp_dir)
|
||||||
|
|
|
@ -261,9 +261,9 @@ function(gp_resolve_item context item exepath dirs resolved_item_var)
|
||||||
|
|
||||||
# Is it already resolved?
|
# Is it already resolved?
|
||||||
#
|
#
|
||||||
if(EXISTS "${resolved_item}")
|
if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
|
||||||
set(resolved 1)
|
set(resolved 1)
|
||||||
endif(EXISTS "${resolved_item}")
|
endif(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}")
|
||||||
|
|
||||||
if(NOT resolved)
|
if(NOT resolved)
|
||||||
if(item MATCHES "@executable_path")
|
if(item MATCHES "@executable_path")
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
project(BundleUtilities)
|
||||||
|
|
||||||
|
###### the various types of dependencies we can have
|
||||||
|
|
||||||
|
# a shared library
|
||||||
|
add_library(shared SHARED shared.cpp shared.h)
|
||||||
|
|
||||||
|
# another shared library
|
||||||
|
add_library(shared2 SHARED shared2.cpp shared2.h)
|
||||||
|
|
||||||
|
# a loadable module (depends on shared2)
|
||||||
|
# test app will load this at runtime
|
||||||
|
add_library(module MODULE module.cpp module.h)
|
||||||
|
set_target_properties(module PROPERTIES PREFIX "")
|
||||||
|
get_target_property(module_loc module LOCATION)
|
||||||
|
target_link_libraries(module shared2)
|
||||||
|
|
||||||
|
# a framework library
|
||||||
|
add_library(framework SHARED framework.cpp framework.h)
|
||||||
|
# TODO: fix problems with local frameworks without rpaths
|
||||||
|
#set_target_properties(framework PROPERTIES FRAMEWORK 1)
|
||||||
|
|
||||||
|
# make sure rpaths are not helping BundleUtilities or the executables
|
||||||
|
set_target_properties(shared shared2 module framework PROPERTIES
|
||||||
|
SKIP_BUILD_RPATH 1)
|
||||||
|
|
||||||
|
|
||||||
|
###### test a Bundle application using dependencies
|
||||||
|
|
||||||
|
set(TESTBUNDLEDIR "${CMAKE_CURRENT_BINARY_DIR}/testdir1")
|
||||||
|
add_executable(testbundleutils1 MACOSX_BUNDLE testbundleutils.cpp)
|
||||||
|
target_link_libraries(testbundleutils1 shared framework ${CMAKE_DL_LIBS})
|
||||||
|
set_target_properties(testbundleutils1 PROPERTIES
|
||||||
|
INSTALL_RPATH "${TESTBUNDLEDIR}"
|
||||||
|
BUILD_WITH_INSTALL_RPATH 1)
|
||||||
|
get_target_property(loc testbundleutils1 LOCATION)
|
||||||
|
|
||||||
|
add_custom_target(testbundleutils1_test ALL
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
"-DINPUT=${loc}"
|
||||||
|
"-DMODULE=${module_loc}"
|
||||||
|
"-DINPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
|
||||||
|
"-DOUTPUTDIR=${TESTBUNDLEDIR}"
|
||||||
|
-P "${CMAKE_CURRENT_SOURCE_DIR}/bundleutils.cmake"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(testbundleutils1_test testbundleutils1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###### test a non-Bundle application using dependencies
|
||||||
|
|
||||||
|
set(TESTBUNDLEDIR "${CMAKE_CURRENT_BINARY_DIR}/testdir2")
|
||||||
|
add_executable(testbundleutils2 testbundleutils.cpp)
|
||||||
|
target_link_libraries(testbundleutils2 shared framework ${CMAKE_DL_LIBS})
|
||||||
|
set_target_properties(testbundleutils2 PROPERTIES
|
||||||
|
INSTALL_RPATH "${TESTBUNDLEDIR}"
|
||||||
|
BUILD_WITH_INSTALL_RPATH 1)
|
||||||
|
get_target_property(loc testbundleutils2 LOCATION)
|
||||||
|
|
||||||
|
add_custom_target(testbundleutils2_test ALL
|
||||||
|
COMMAND ${CMAKE_COMMAND}
|
||||||
|
"-DINPUT=${loc}"
|
||||||
|
"-DMODULE=${module_loc}"
|
||||||
|
"-DINPUTDIR=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}"
|
||||||
|
"-DOUTPUTDIR=${TESTBUNDLEDIR}"
|
||||||
|
-P "${CMAKE_CURRENT_SOURCE_DIR}/bundleutils.cmake"
|
||||||
|
)
|
||||||
|
add_dependencies(testbundleutils2_test testbundleutils2)
|
|
@ -0,0 +1,44 @@
|
||||||
|
|
||||||
|
# clean passed in arguments
|
||||||
|
get_filename_component(INPUT ${INPUT} ABSOLUTE)
|
||||||
|
get_filename_component(INPUTDIR ${INPUTDIR} ABSOLUTE)
|
||||||
|
|
||||||
|
message("INPUT = ${INPUT}")
|
||||||
|
message("MODULE = ${MODULE}")
|
||||||
|
message("INPUTDIR = ${INPUTDIR}")
|
||||||
|
message("OUTPUTDIR = ${OUTPUTDIR}")
|
||||||
|
|
||||||
|
# compute location to install/test things
|
||||||
|
file(RELATIVE_PATH relative_exe "${INPUTDIR}" "${INPUT}")
|
||||||
|
set(OUTPUT "${OUTPUTDIR}/${relative_exe}")
|
||||||
|
message("OUTPUT = ${OUTPUT}")
|
||||||
|
get_filename_component(EXE_DIR "${OUTPUT}" PATH)
|
||||||
|
get_filename_component(MODULE_NAME "${MODULE}" NAME)
|
||||||
|
set(OUTPUT_MODULE "${EXE_DIR}/${MODULE_NAME}")
|
||||||
|
message("OUTPUTMODULE = ${OUTPUT_MODULE}")
|
||||||
|
|
||||||
|
# clean output dir
|
||||||
|
file(REMOVE_RECURSE "${OUTPUTDIR}")
|
||||||
|
# copy the app and plugin to installation/testing directory
|
||||||
|
configure_file("${INPUT}" "${OUTPUT}" COPYONLY)
|
||||||
|
configure_file("${MODULE}" "${OUTPUT_MODULE}" COPYONLY)
|
||||||
|
|
||||||
|
# have BundleUtilities grab all dependencies and
|
||||||
|
# check that the app runs
|
||||||
|
|
||||||
|
# for this test we'll override location to put all dependencies
|
||||||
|
# (in the same dir as the app)
|
||||||
|
# this shouldn't be necessary except for the non-bundle case on Mac
|
||||||
|
function(gp_item_default_embedded_path_override item path)
|
||||||
|
set(path "@executable_path" PARENT_SCOPE)
|
||||||
|
endfunction(gp_item_default_embedded_path_override)
|
||||||
|
|
||||||
|
include(BundleUtilities)
|
||||||
|
fixup_bundle("${OUTPUT}" "${OUTPUT_MODULE}" "${INPUTDIR}")
|
||||||
|
|
||||||
|
# make sure we can run the app
|
||||||
|
execute_process(COMMAND "${OUTPUT}" RESULT_VARIABLE result)
|
||||||
|
|
||||||
|
if(NOT result STREQUAL "0")
|
||||||
|
message(FATAL_ERROR " failed to execute test program")
|
||||||
|
endif(NOT result STREQUAL "0")
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#include "framework.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
void framework()
|
||||||
|
{
|
||||||
|
printf("framework\n");
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
#ifndef framework_h
|
||||||
|
#define framework_h
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# ifdef framework_EXPORTS
|
||||||
|
# define FRAMEWORK_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define FRAMEWORK_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define FRAMEWORK_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void FRAMEWORK_EXPORT framework();
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
#include "module.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "shared2.h"
|
||||||
|
|
||||||
|
void module()
|
||||||
|
{
|
||||||
|
printf("module\n");
|
||||||
|
shared2();
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
|
||||||
|
#ifndef module_h
|
||||||
|
#define module_h
|
||||||
|
|
||||||
|
void module();
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
void shared()
|
||||||
|
{
|
||||||
|
printf("shared\n");
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
#ifndef shared_h
|
||||||
|
#define shared_h
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# ifdef shared_EXPORTS
|
||||||
|
# define SHARED_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define SHARED_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define SHARED_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SHARED_EXPORT shared();
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
#include "shared2.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
|
||||||
|
void shared2()
|
||||||
|
{
|
||||||
|
printf("shared2\n");
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
|
||||||
|
#ifndef shared2_h
|
||||||
|
#define shared2_h
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
# ifdef shared2_EXPORTS
|
||||||
|
# define SHARED2_EXPORT __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define SHARED2_EXPORT __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define SHARED2_EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void SHARED2_EXPORT shared2();
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
#include "framework.h"
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include "dlfcn.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int, char**)
|
||||||
|
{
|
||||||
|
framework();
|
||||||
|
shared();
|
||||||
|
|
||||||
|
#if defined(WIN32)
|
||||||
|
HANDLE lib = LoadLibraryA("module.dll");
|
||||||
|
#else
|
||||||
|
void* lib = dlopen("module.so", RTLD_LAZY);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return lib == 0 ? 1 : 0;
|
||||||
|
}
|
|
@ -193,6 +193,25 @@ IF(BUILD_TESTING)
|
||||||
|
|
||||||
LIST(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX})
|
LIST(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX})
|
||||||
|
|
||||||
|
|
||||||
|
# run test for BundleUtilities on supported platforms
|
||||||
|
if(CMAKE_SYSTEM_NAME MATCHES "Windows" OR
|
||||||
|
CMAKE_SYSTEM_NAME MATCHES "Linux" OR
|
||||||
|
CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||||
|
ADD_TEST(BundleUtilities ${CMAKE_CTEST_COMMAND}
|
||||||
|
--build-and-test
|
||||||
|
"${CMake_SOURCE_DIR}/Tests/BundleUtilities"
|
||||||
|
"${CMake_BINARY_DIR}/Tests/BundleUtilities"
|
||||||
|
--build-generator ${CMAKE_TEST_GENERATOR}
|
||||||
|
--build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
|
||||||
|
--build-project BundleUtilities
|
||||||
|
--test-command testdir2/testbundleutils2
|
||||||
|
)
|
||||||
|
LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleUtilities")
|
||||||
|
endif(CMAKE_SYSTEM_NAME MATCHES "Windows" OR
|
||||||
|
CMAKE_SYSTEM_NAME MATCHES "Linux" OR
|
||||||
|
CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||||
|
|
||||||
SET(CMAKE_BUILD_TEST_SOURCE_DIR "${CMake_SOURCE_DIR}/Tests/COnly")
|
SET(CMAKE_BUILD_TEST_SOURCE_DIR "${CMake_SOURCE_DIR}/Tests/COnly")
|
||||||
SET(CMAKE_BUILD_TEST_BINARY_DIR "${CMake_BINARY_DIR}/Tests/CMakeBuildCOnly")
|
SET(CMAKE_BUILD_TEST_BINARY_DIR "${CMake_BINARY_DIR}/Tests/CMakeBuildCOnly")
|
||||||
CONFIGURE_FILE("${CMake_SOURCE_DIR}/Tests/CMakeBuildTest.cmake.in"
|
CONFIGURE_FILE("${CMake_SOURCE_DIR}/Tests/CMakeBuildTest.cmake.in"
|
||||||
|
|
Loading…
Reference in New Issue