Skip to content

Commit

Permalink
Apple MacOS Packaging and App signing
Browse files Browse the repository at this point in the history
Successful cpack with fixup bundle on arm64 M2.
Signing of the .app and all binary dependencies within the cmake install process.
Fixed minor issues with OSX compilation.
  • Loading branch information
brunoherbelin committed Sep 1, 2024
1 parent 7788019 commit da0782d
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 67 deletions.
19 changes: 14 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,17 +61,26 @@ if(UNIX)
set(CMAKE_SKIP_RPATH TRUE)
set(OpenGL_DIR /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/)

# set(CMAKE_OSX_ARCHITECTURES "x86_64")
# set(CMAKE_OSX_DEPLOYMENT_TARGET "11")

set(CMAKE_OSX_ARCHITECTURES "arm64")
set(CMAKE_OSX_DEPLOYMENT_TARGET "13")
# MacOS target
set(CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "")
set(CMAKE_OSX_DEPLOYMENT_TARGET "13" CACHE STRING "")

# CPACK
set(CPACK_SYSTEM_NAME "OSX_${CMAKE_OSX_DEPLOYMENT_TARGET}_${CMAKE_OSX_ARCHITECTURES}")
set(CPACK_GENERATOR DragNDrop)
set(CPACK_BINARY_DRAGNDROP ON)

# Apple ID code signing
set(APPLE_CODESIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/osx/entitlements.plist")
## team ID, for example if your certificate is: Developer ID Application: JOHN, DOE (X4MF6H9XZ6) the team ID is: X4MF6H9XZ6
set(APPLE_CODESIGN_TEAM "" CACHE STRING "")
## Apple identity, in the form Developer ID Application
set(APPLE_CODESIGN_IDENTITY "Developer ID Application:" CACHE STRING "")
## Apple keychain profile for app-specific password
## 1. Create a password for "vimix" at https://support.apple.com/en-us/102654
## 2. Run e.g.
## xcrun notarytool store-credentials "vimix" --apple-id <email_login_apple_id> --team-id <team> --password <string_given_https://appleid.apple.com/account/manage>
set(APPLE_CODESIGN_STORED_CREDENTIAL "vimix" CACHE STRING "")

# find icu4c in OSX (pretty well hidden...)
set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:/usr/local/opt/icu4c/lib/pkgconfig:/opt/homebrew/opt/icu4c/lib/pkgconfig")
Expand Down
5 changes: 3 additions & 2 deletions cmake/modules/FindGStreamer.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ find_package(PkgConfig)
if (PKG_CONFIG_FOUND)
pkg_check_modules(PKG_GSTREAMER gstreamer-${GSTREAMER_ABI_VERSION})
execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE}
ARGS --variable pluginsdir gstreamer-${GSTREAMER_ABI_VERSION}
OUTPUT_VARIABLE PKG_GSTREAMER_PLUGIN_DIR)
--variable pluginsdir gstreamer-${GSTREAMER_ABI_VERSION}
OUTPUT_VARIABLE PKG_GSTREAMER_PLUGIN_DIR_TMP)
string(STRIP ${PKG_GSTREAMER_PLUGIN_DIR_TMP} PKG_GSTREAMER_PLUGIN_DIR)
endif()

find_library(GSTREAMER_LIBRARY
Expand Down
176 changes: 116 additions & 60 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,11 @@ IF(APPLE)

# set the Info.plist file
set(MACOSX_BUNDLE_PLIST_FILE ${CMAKE_SOURCE_DIR}/osx/Info.plist.in)
set_target_properties(${VMIX_BINARY} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_PLIST_FILE})
set_target_properties(${VMIX_BINARY} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_PLIST_FILE}
)

# link with base frameworks
set(PLATFORM_LIBS
"-framework CoreFoundation"
"-framework Appkit"
Expand Down Expand Up @@ -190,6 +193,11 @@ IF(APPLE)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_BINARY_DRAGNDROP ON)

set(CPACK_BUNDLE_NAME "vimix.app")
set(CPACK_BUNDLE_PLIST ${CMAKE_SOURCE_DIR}/osx/Info.plist.in)
set(CPACK_BUNDLE_ICON ${CMAKE_SOURCE_DIR}/osx/vimix.icns)
set(CPACK_BUNDLE_APPLE_CERT_APP ${APPLE_CODESIGN_IDENTITY})
set(CPACK_BUNDLE_APPLE_ENTITLEMENTS ${APPLE_CODESIGN_ENTITLEMENTS})

install(TARGETS ${VMIX_BINARY}
CONFIGURATIONS Release RelWithDebInfo
Expand All @@ -198,91 +206,139 @@ IF(APPLE)
)

# create GST plugins directory in Bundle Resources subfolder
set(plugin_dest_dir vimix.app/Contents/Resources/)

### TODO configure auto to find installation dir of gst

message(STATUS "install gst-plugins ${PKG_GSTREAMER_PLUGIN_DIR}")
message(STATUS "install gst-plugins-base ${PKG_GSTREAMER_BASE_PLUGIN_DIR}")

if (PKG_CONFIG_FOUND)
pkg_check_modules(PKG_GSTREAMER_PLUGINS_BAD gstreamer-plugins-bad-${GSTREAMER_ABI_VERSION})
set(PKG_GSTREAMER_BAD_PLUGIN_DIR ${PKG_GSTREAMER_PLUGINS_BAD_LIBDIR}/gstreamer-${GSTREAMER_ABI_VERSION})
message(STATUS "install gst-plugins-bad ${PKG_GSTREAMER_BAD_PLUGIN_DIR}")
endif()
set(plugin_dest_dir ${CPACK_BUNDLE_NAME}/Contents/Resources/)

### install gst plugins
message(STATUS "Install with gst-plugins ${PKG_GSTREAMER_PLUGIN_DIR}")
install(DIRECTORY "${PKG_GSTREAMER_PLUGIN_DIR}" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)
list(APPEND GSTPLUGINS_EXCLUDE "libgstgtk4.dylib" "libgstgtk.dylib" "libgstpython.dylib")

# intall the gst-plugin-scanner program (used by plugins at load time)
# install the gst-plugin-scanner program (used by plugins at load time)
set(PKG_GSTREAMER_SCANNER "${PKG_GSTREAMER_PREFIX}/libexec/gstreamer-1.0/gst-plugin-scanner")
message(STATUS "install gst-plugin-scanner ${PKG_GSTREAMER_SCANNER}")
message(STATUS "Install with gst-plugin-scanner ${PKG_GSTREAMER_SCANNER}")
install(FILES "${PKG_GSTREAMER_SCANNER}"
DESTINATION "${plugin_dest_dir}"
PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
COMPONENT Runtime
)

# Install the gst-plugins (all those installed with brew )
install(DIRECTORY "${PKG_GSTREAMER_PLUGIN_DIR}" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)
install(DIRECTORY "${PKG_GSTREAMER_BASE_PLUGIN_DIR}" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)
install(DIRECTORY "${PKG_GSTREAMER_BAD_PLUGIN_DIR}" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)

install(DIRECTORY "/usr/local/Cellar/gst-plugins-good/1.22.6/lib/gstreamer-1.0" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)
install(DIRECTORY "/usr/local/Cellar/gst-plugins-ugly/1.22.6/lib/gstreamer-1.0" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)
install(DIRECTORY "/usr/local/Cellar/gst-libav/1.22.6/lib/gstreamer-1.0" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)

# # install locally recompiled & installed gst-plugins (because not included in brew package)
# install(FILES "/usr/local/lib/gstreamer-1.0/libgstapplemedia.dylib"
# "/usr/local/lib/gstreamer-1.0/libgstde265.dylib"
# "/usr/local/lib/gstreamer-1.0/libgstx265.dylib"
# DESTINATION "${plugin_dest_dir}/gstreamer-1.0" COMPONENT Runtime)

# install frei0r plugins (dependencies of gstreamer-1.0/libgstfrei0r.dylib plugin)
install(FILES "/usr/local/Cellar/frei0r/2.3.1/lib/frei0r-1/lissajous0r.so"
"/usr/local/Cellar/frei0r/2.3.1/lib/frei0r-1/rgbnoise.so"
DESTINATION "${plugin_dest_dir}/frei0r-1" COMPONENT Runtime)


# ICU DATA LIB GST dependency : undocumented and hacked here : seems to work
# install(FILES "${ICU_LINK_LIBRARIES}" DESTINATION "${plugin_dest_dir}/gstreamer-1.0" COMPONENT Runtime)
# install(FILES "/usr/local/Cellar/icu4c/73.2/lib/libicudata.73.2.dylib" DESTINATION "${plugin_dest_dir}/gstreamer-1.0" RENAME "libicudata.73.dylib" COMPONENT Runtime)
message(STATUS "install ${ICU_LINK_LIBRARIES} from ${ICU_LIBRARY_DIRS}")
pkg_check_modules(FREI0R QUIET frei0r)
set(PKG_FREI0R_PLUGIN_DIR ${FREI0R_LIBDIR}/frei0r-1)
message(STATUS "Install with frei0r plugins ${PKG_FREI0R_PLUGIN_DIR}")
install(DIRECTORY "${PKG_FREI0R_PLUGIN_DIR}" DESTINATION "${plugin_dest_dir}" COMPONENT Runtime)

# package runtime fixup bundle
set(APPS "\${CMAKE_INSTALL_PREFIX}/vimix.app")
set(APPS "\${CMAKE_INSTALL_PREFIX}/${CPACK_BUNDLE_NAME}")

## APPLE BUNDLE FIX
## with install_name_tool using cmake 'fixup_bundle'
install(CODE "
file(GLOB_RECURSE GSTPLUGINS \"\${CMAKE_INSTALL_PREFIX}/${plugin_dest_dir}/gstreamer-1.0/*.dylib\")
list(APPEND LIBS_PATH \"${ICU_LIBRARY_DIRS}\" \"/usr/local/lib\" \"/usr/local/Cellar/libarchive/3.7.2/lib\")
include(BundleUtilities)
set(BU_CHMOD_BUNDLE_ITEMS TRUE)
fixup_bundle(\"${APPS}\" \"\${GSTPLUGINS}\" \"\${LIBS_PATH}\")
"
COMPONENT Runtime
file(GLOB_RECURSE GSTPLUGINS \"\${CMAKE_INSTALL_PREFIX}/${plugin_dest_dir}/gstreamer-1.0/*.dylib\")
foreach(PLUGIN \${GSTPLUGINS})
set(ADD_PLUGIN true)
foreach(EXCLUDED ${GSTPLUGINS_EXCLUDE})
string(FIND \${PLUGIN} \${EXCLUDED} _found)
if(NOT \${_found} EQUAL -1)
file(REMOVE \${PLUGIN})
set(ADD_PLUGIN false)
endif()
endforeach()
if(ADD_PLUGIN)
list(APPEND ALLPLUGINS \${PLUGIN})
endif()
endforeach()
file(GLOB FREI0RPLUGINS \"\${CMAKE_INSTALL_PREFIX}/${plugin_dest_dir}/frei0r-1/*.so\")
list(APPEND ALLPLUGINS \${FREI0RPLUGINS} )
list(LENGTH ALLPLUGINS SIZE)
message(\" - Adding \${SIZE} plugins to bundle...\")
include(BundleUtilities)
set(BU_CHMOD_BUNDLE_ITEMS TRUE)
fixup_bundle(\"${APPS}\" \"\${ALLPLUGINS}\" \"/opt/homebrew/lib\" IGNORE_ITEM \"Python\")
file(REMOVE_RECURSE \"${APPS}/Contents/Frameworks/Python.framework\")
"
COMPONENT Runtime
)

set(APPLE_CODESIGN_IDENTITY "" CACHE STRING "")
## APPLE CODE SIGNING
## Sign the bundle and ALL binary (executables and dynamic library)
string(LENGTH "${APPLE_CODESIGN_IDENTITY}" APPLE_CODESIGN_IDENTITY_LENGHT)
if( ${APPLE_CODESIGN_IDENTITY_LENGHT} LESS 40 )
message(STATUS "Not signing bundle. Specify APPLE_CODESIGN_IDENTITY to cmake before running cpack to sign")
message(STATUS "Not signing bundle. Specify APPLE_CODESIGN_IDENTITY to cmake before running cpack if you want to sign the bundle")
else()
message(STATUS "Signing bundle with identity " ${APPLE_CODESIGN_IDENTITY})
install(CODE "
cmake_policy(VERSION 3.8)
file(GLOB_RECURSE DEPENDENCIES ${APPS}/Contents/*.dylib)
file(GLOB_RECURSE SO_DEPENDENCIES ${APPS}/Contents/*.so)
list(APPEND DEPENDENCIES \${SO_DEPENDENCIES})
foreach(DEP \${DEPENDENCIES})
execute_process(COMMAND
codesign --verify --verbose=0 --force
--sign \"${APPLE_CODESIGN_IDENTITY}\"
\"\${DEP}\"
)
endforeach()
list(LENGTH DEPENDENCIES SIZE)
message(\" - \${SIZE} dependency libraries signed.\")
message(\" - Signing executables in ${APPS}\")
execute_process(COMMAND
codesign -vvv --force
--options runtime --timestamp
--entitlements \"${APPLE_CODESIGN_ENTITLEMENTS}\"
--sign \"${APPLE_CODESIGN_IDENTITY}\"
\"${APPS}/Contents/MacOS/vimix\"
\"${APPS}/Contents/Resources/gst-plugin-scanner\"
)
message(\" - Signing bundle ${APPS}\")
execute_process(COMMAND
codesign -vvv --deep --force
--entitlements \"${APPLE_CODESIGN_ENTITLEMENTS}\"
--sign \"${APPLE_CODESIGN_IDENTITY}\"
\"${APPS}\" )
codesign -vvv --force --strict
--options runtime --timestamp
--entitlements \"${APPLE_CODESIGN_ENTITLEMENTS}\"
--sign \"${APPLE_CODESIGN_IDENTITY}\"
\"${APPS}\"
)
"
COMPONENT Runtime
)
# install(CODE "
# include(BundleUtilities)
# get_bundle_all_executables(\"${APPS}\" EXECUTABLES)
# foreach(EXE \${EXECUTABLES})
# message(\"SIGNING EXECUTABLE \${EXE}\")
# execute_process(COMMAND
# codesign --verbose=2 --force
# --sign \"${APPLE_CODESIGN_IDENTITY}\"
# \"\${EXE}\"
# )
# endforeach()
# "
# COMPONENT Runtime
# )
# install(CODE "
# execute_process(COMMAND
# codesign --verbose=2 --force
# --sign \"${APPLE_CODESIGN_IDENTITY}\"
# \"${DMGS}\"
# )
# message(\"codesign ${DMGS} \")
# "
# COMPONENT Runtime
# )
# install(CODE "
# execute_process(COMMAND
# xcrun notarytool submit \"${DMGS}\"
# --keychain-profile \"${APPLE_CODESIGN_STORED_CREDENTIAL}\"
# --wait
# )
# message(\"notary tool ${DMGS} ${APPLE_CODESIGN_STORED_CREDENTIAL} \")
# "
# COMPONENT Runtime
# )
endif()

# # package runtime fixup bundle and codesign
# set(BUNDLE_NAME "vimix.app")
# set(BUNDLE_LIBS_DIR "${plugin_dest_dir}/gstreamer-1.0")
# set(BUNDLE_DIRS "${ICU_LIBRARY_DIRS}")
# set(APPLE_CODESIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/osx/entitlements.plist")
# install (SCRIPT "${CMAKE_SOURCE_DIR}/osx/PostInstall.cmake")

# configure_file(cmake/modules/BundleInstall.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/BundleInstall.cmake" @ONLY)
# install(SCRIPT "${CMAKE_CURRENT_BINARY_DIR}/BundleInstall.cmake" COMPONENT Runtime)

ELSE(APPLE)

Expand Down
2 changes: 2 additions & 0 deletions src/RenderingManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,7 @@ void RenderingWindow::setTitle(const std::string &title)

void RenderingWindow::setIcon(const std::string &resource)
{
#ifndef APPLE
size_t fpsize = 0;
const char *fp = Resource::getData(resource, &fpsize);
if (fp != nullptr && window_) {
Expand All @@ -773,6 +774,7 @@ void RenderingWindow::setIcon(const std::string &resource)
glfwSetWindowIcon( window_, 1, &icon );
free( icon.pixels );
}
#endif
}

GLFWmonitor *RenderingWindow::monitor()
Expand Down

0 comments on commit da0782d

Please sign in to comment.