diff --git a/CMakeLists.txt b/CMakeLists.txt index a1ca31de..816ceb25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,12 +196,67 @@ if(NOT BOLT_DEV_LAUNCHER_DIRECTORY) endif() # This line needs to be updated manually with any new/deleted object files; cmake discourages GLOBbing source files -add_executable(bolt +set(BOLT_SRCS modules/fmt/src/format.cc src/main.cxx src/browser.cxx src/browser/app.cxx src/browser/client.cxx src/browser/resource_handler.cxx src/browser/window_launcher.cxx ${WINDOW_LAUNCHER_OS_SPECIFIC} src/mime.cxx src/file_manager/directory.cxx client_cmake_gen.cxx ${BOLT_FILE_MANAGER_LAUNCHER_GEN} ) +if(APPLE) + add_executable(bolt MACOSX_BUNDLE ${BOLT_SRCS}) + # Copy the CEF framework into the Frameworks directory. + add_custom_command( + TARGET bolt + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CEF_ROOT}/${CMAKE_BUILD_TYPE}/Chromium Embedded Framework.framework" + "${CMAKE_BINARY_DIR}/bolt.app/Contents/Frameworks/Chromium Embedded Framework.framework" + VERBATIM + ) + + set(BOLT_HELPER_SRCS + mac/process_helper.cc + ) + + # Create the multiple Helper app bundle targets. + foreach(_suffix_list ${CEF_HELPER_APP_SUFFIXES}) + # Convert to a list and extract the suffix values. + string(REPLACE ":" ";" _suffix_list ${_suffix_list}) + list(GET _suffix_list 0 _name_suffix) + list(GET _suffix_list 1 _target_suffix) + list(GET _suffix_list 2 _plist_suffix) + + # Define Helper target and output names. + set(_helper_target "Bolt_Helper${_target_suffix}") + set(_helper_output_name "Bolt Helper${_name_suffix}") + + # Create Helper executable target. + add_executable(${_helper_target} MACOSX_BUNDLE ${BOLT_HELPER_SRCS}) + add_dependencies(${_helper_target} libcef_dll_wrapper) + target_include_directories(${_helper_target} PUBLIC "${CEF_ROOT}") + set_target_properties(${_helper_target} PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF) + target_link_libraries(${_helper_target} libcef_dll_wrapper ${CEF_STANDARD_LIBS}) + set_target_properties(${_helper_target} PROPERTIES + OUTPUT_NAME ${_helper_output_name} + ) + + # Add the Helper as a dependency of the main executable target. + add_dependencies(bolt "${_helper_target}") + + # Copy the Helper app bundle into the Frameworks directory. + add_custom_command( + TARGET bolt + POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${CMAKE_BINARY_DIR}/${_helper_output_name}.app" + "${CMAKE_BINARY_DIR}/bolt.app/Contents/Frameworks/${_helper_output_name}.app" + VERBATIM + ) + endforeach() +else() + add_executable(bolt ${BOLT_SRCS}) +endif() + # Various build properties target_include_directories(bolt PUBLIC ${CEF_ROOT} modules/fmt/include) set_target_properties(bolt PROPERTIES CXX_STANDARD 20 CXX_EXTENSIONS OFF) @@ -224,7 +279,15 @@ elseif(WIN32) target_link_libraries(bolt PUBLIC "${CEF_ROOT}/${CMAKE_BUILD_TYPE}/libcef.lib") target_link_libraries(bolt PUBLIC "${CEF_ROOT}/${CMAKE_BUILD_TYPE}/cef_sandbox.lib") elseif(APPLE) - # TODO: mac support + execute_process( + COMMAND brew --prefix libarchive + OUTPUT_VARIABLE LIBARCHIVE_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE + COMMAND_ERROR_IS_FATAL ANY + ) + set(LibArchive_INCLUDE_DIR "${LIBARCHIVE_PREFIX}/include") + find_package(LibArchive REQUIRED) + target_link_libraries(bolt PRIVATE LibArchive::LibArchive) endif() # compilation setting for enabling chromium dev tools @@ -256,15 +319,14 @@ find_package(PkgConfig REQUIRED) pkg_check_modules(GTK3 REQUIRED gtk+-3.0) target_include_directories(bolt PUBLIC ${GTK3_INCLUDE_DIRS}) target_link_libraries(bolt PUBLIC ${GTK3_LIBRARIES}) -if(MSVC) +if(MSVC OR APPLE) target_link_directories(bolt PUBLIC ${GTK3_LIBRARY_DIRS}) endif() +install(TARGETS bolt DESTINATION ${BOLT_CEF_INSTALLDIR}/bolt-launcher) # Install commands for target dir layout - as per https://bitbucket.org/chromiumembedded/cef/wiki/Tutorial.md if(APPLE) - # TODO: mac support else() - install(TARGETS bolt DESTINATION ${BOLT_CEF_INSTALLDIR}/bolt-launcher) install(DIRECTORY "${CEF_ROOT}/${CMAKE_BUILD_TYPE}/" "${CEF_ROOT}/Resources/" DESTINATION ${BOLT_CEF_INSTALLDIR}/bolt-launcher USE_SOURCE_PERMISSIONS) endif() diff --git a/README.md b/README.md index 00ad4f20..a90857a0 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,14 @@ Windows builds have only been tested using Visual Studio 2022 (a.k.a. Visual Stu ### Mac Not yet supported + + +```bash +brew install cmake pkg-config gtk+3 libarchive +cmake -S . -B build -D BOLT_SKIP_LIBRARIES=True -D CMAKE_BUILD_TYPE=Release -D CEF_ROOT=$HOME/Downloads/cef_binary_122.1.13+gde5b724+chromium-122.0.6261.130_macosarm64_minimal +cmake --build build +``` + ## Maintenance When doing the initial cmake setup step, the following options exist which you may find useful. These are to be used for local development only. - `-D BOLT_HTML_DIR=/some/directory`: the location of the launcher's internal webpage content, `html/` by default diff --git a/entitlements-helper.plist b/entitlements-helper.plist new file mode 100644 index 00000000..4228cf17 --- /dev/null +++ b/entitlements-helper.plist @@ -0,0 +1,12 @@ + + + + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.disable-library-validation + + com.apple.security.cs.allow-jit + + + diff --git a/mac/process_helper.cc b/mac/process_helper.cc new file mode 100644 index 00000000..0cd6e0bd --- /dev/null +++ b/mac/process_helper.cc @@ -0,0 +1,33 @@ +#include "include/cef_app.h" +#include "include/wrapper/cef_library_loader.h" + +// When generating projects with CMake the CEF_USE_SANDBOX value will be defined +// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable +// use of the sandbox. +#if defined(CEF_USE_SANDBOX) +#include "include/cef_sandbox_mac.h" +#endif + +// Entry point function for sub-processes. +int main(int argc, char* argv[]) { +#if defined(CEF_USE_SANDBOX) + // Initialize the macOS sandbox for this helper process. + CefScopedSandboxContext sandbox_context; + if (!sandbox_context.Initialize(argc, argv)) { + return 1; + } +#endif + + // Load the CEF framework library at runtime instead of linking directly + // as required by the macOS sandbox implementation. + CefScopedLibraryLoader library_loader; + if (!library_loader.LoadInHelper()) { + return 1; + } + + // Provide CEF with command-line arguments. + CefMainArgs main_args(argc, argv); + + // Execute the sub-process. + return CefExecuteProcess(main_args, nullptr, nullptr); +} diff --git a/src/main.cxx b/src/main.cxx index a346c01e..a0443d6f 100644 --- a/src/main.cxx +++ b/src/main.cxx @@ -16,6 +16,10 @@ #include #endif +#if defined(__APPLE__) +#include "include/wrapper/cef_library_loader.h" +#endif + #if defined(CEF_X11) #include int XErrorHandlerImpl(Display* display, XErrorEvent* event) { @@ -313,6 +317,25 @@ bool LockXdgDirectories(std::filesystem::path& config_dir, std::filesystem::path } #endif +#if defined(__APPLE__) +int main(int argc, char* argv[]) { + // Dynamically load the CEF framework library. + CefScopedLibraryLoader library_loader; + if (!library_loader.LoadInMain()) + return 1; + + // Provide CEF with command-line arguments. + CefMainArgs main_args(argc, argv); + Browser::App cef_app_; + CefRefPtr cef_app = &cef_app_; + + return BoltRunBrowserProcess(main_args, cef_app); +} +bool LockXdgDirectories(std::filesystem::path& config_dir, std::filesystem::path& data_dir) { + return true; +} +#endif + // all these features exist in gtk3 and are deprecated for no reason at all, so ignore deprecation warnings #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations"