macOS: Load the CEF framework using dlopen instead of direct linking (issue #2459)

This is a prerequisite for using the Chromium V2 sandbox.
This commit is contained in:
Marshall Greenblatt 2018-07-27 11:39:53 -04:00
parent 0fb03e7aa1
commit fcad76b405
21 changed files with 2722 additions and 88 deletions

View File

@ -1004,6 +1004,10 @@ static_library("libcef_dll_wrapper") {
gypi_paths2.libcef_dll_wrapper_sources_common +
gypi_paths.autogen_client_side
if (is_mac) {
sources += gypi_paths2.libcef_dll_wrapper_sources_mac
}
defines = [ "WRAPPING_CEF_SHARED" ]
configs += [ ":libcef_dll_wrapper_config" ]
@ -1463,14 +1467,9 @@ if (is_mac) {
":libcef_static",
]
# Both the main app executable and helper executables need to link the
# framework. Because they are at different directory depths, using
# @executable_path as the install_name would require using install_name_tool
# on one of the executables. However install_name_tool only operates
# in-place, which is problematic to express in GN. Instead, use rpath-based
# loading.
# We don't link the framework so just use the path from the main executable.
ldflags = [
"-Wl,-install_name,@rpath/Frameworks/$output_name.framework/$output_name",
"-Wl,-install_name,@executable_path/../Frameworks/$output_name.framework/$output_name",
"-compatibility_version",
cef_dylib_version,
"-current_version",
@ -1569,7 +1568,6 @@ if (is_mac) {
sources = invoker.helper_sources
deps = [
":cef_framework+link",
":libcef_dll_wrapper",
]
if (defined(invoker.helper_deps)) {
@ -1578,9 +1576,9 @@ if (is_mac) {
ldflags = [
# The helper is in $app_name.app/Contents/Frameworks/$app_name Helper.app/Contents/MacOS/
# so set rpath up to Contents/ so that the loader can find Frameworks/.
# so set rpath up to the base.
"-rpath",
"@executable_path/../../../..",
"@executable_path/../../../../../..",
]
info_plist_target = ":${app_name}_helper_plist"
@ -1594,7 +1592,7 @@ if (is_mac) {
]
public_deps = [
":cef_framework+link",
":cef_framework",
":${app_name}_helper_app",
]
@ -1630,13 +1628,6 @@ if (is_mac) {
libs = invoker.libs
}
ldflags = [
# The main app is at $app_name.app/Contents/MacOS/$app_name
# so set rpath up to Contents/ so that the loader can find Frameworks/.
"-rpath",
"@executable_path/../",
]
info_plist_target = ":${app_name}_plist"
}
}
@ -1687,6 +1678,7 @@ if (is_mac) {
helper_sources = gypi_paths2.includes_mac +
gypi_paths2.includes_common +
gypi_paths2.includes_wrapper +
gypi_paths2.includes_wrapper_mac +
gypi_paths2.shared_sources_common +
gypi_paths2.shared_sources_renderer +
gypi_paths2.shared_sources_mac_helper +
@ -1700,6 +1692,7 @@ if (is_mac) {
sources = gypi_paths2.includes_mac +
gypi_paths2.includes_common +
gypi_paths2.includes_wrapper +
gypi_paths2.includes_wrapper_mac +
gypi_paths2.shared_sources_browser +
gypi_paths2.shared_sources_common +
gypi_paths2.shared_sources_mac +
@ -1757,6 +1750,7 @@ if (is_mac) {
helper_sources = gypi_paths2.includes_mac +
gypi_paths2.includes_common +
gypi_paths2.includes_wrapper +
gypi_paths2.includes_wrapper_mac +
gypi_paths2.cefsimple_sources_mac_helper
helper_deps = [
":libcef_dll_wrapper",
@ -1766,6 +1760,7 @@ if (is_mac) {
sources = gypi_paths2.includes_mac +
gypi_paths2.includes_common +
gypi_paths2.includes_wrapper +
gypi_paths2.includes_wrapper_mac +
gypi_paths2.cefsimple_sources_common +
gypi_paths2.cefsimple_sources_mac
deps = [
@ -1826,6 +1821,7 @@ if (is_mac) {
sources = gypi_paths2.includes_mac +
gypi_paths2.includes_common +
gypi_paths2.includes_wrapper +
gypi_paths2.includes_wrapper_mac +
gypi_paths2.shared_sources_browser +
gypi_paths2.shared_sources_common +
gypi_paths2.shared_sources_mac +

View File

@ -65,6 +65,9 @@
'include/wrapper/cef_xml_object.h',
'include/wrapper/cef_zip_archive.h',
],
'includes_wrapper_mac': [
'include/wrapper/cef_library_loader.h',
],
'includes_win': [
'include/base/internal/cef_atomicops_x86_msvc.h',
'include/base/internal/cef_bind_internal_win.h',
@ -141,6 +144,10 @@
'libcef_dll/wrapper/libcef_dll_wrapper.cc',
'libcef_dll/wrapper/libcef_dll_wrapper2.cc',
],
'libcef_dll_wrapper_sources_mac': [
'libcef_dll/wrapper/cef_library_loader_mac.mm',
'libcef_dll/wrapper/libcef_dll_dylib.cc',
],
'shared_sources_browser': [
'tests/shared/browser/client_app_browser.cc',
'tests/shared/browser/client_app_browser.h',

View File

@ -185,22 +185,6 @@ endif(OS_LINUX)
if(OS_MACOSX)
# Fix the framework rpath in the helper executable.
macro(FIX_MACOSX_HELPER_FRAMEWORK_RPATH target)
# The helper is in $app_name.app/Contents/Frameworks/$app_name Helper.app/Contents/MacOS/
# so set rpath up to Contents/ so that the loader can find Frameworks/.
set_target_properties(${target} PROPERTIES INSTALL_RPATH "@executable_path/../../../..")
set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
endmacro()
# Fix the framework rpath in the main executable.
macro(FIX_MACOSX_MAIN_FRAMEWORK_RPATH target)
# The main app is at $app_name.app/Contents/MacOS/$app_name
# so set rpath up to Contents/ so that the loader can find Frameworks/.
set_target_properties(${target} PROPERTIES INSTALL_RPATH "@executable_path/..")
set_target_properties(${target} PROPERTIES BUILD_WITH_INSTALL_RPATH TRUE)
endmacro()
# Manually process and copy over resource files.
macro(COPY_MACOSX_RESOURCES resource_list prefix_list target source_dir app_path)
foreach(FILENAME ${resource_list})

View File

@ -313,10 +313,6 @@ if(OS_MACOSX)
set(CEF_BINARY_DIR "${_CEF_ROOT}/$<CONFIGURATION>")
set(CEF_BINARY_DIR_DEBUG "${_CEF_ROOT}/Debug")
set(CEF_BINARY_DIR_RELEASE "${_CEF_ROOT}/Release")
# CEF library paths.
set(CEF_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/Chromium Embedded Framework.framework/Chromium Embedded Framework")
set(CEF_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/Chromium Embedded Framework.framework/Chromium Embedded Framework")
endif()

View File

@ -0,0 +1,116 @@
// Copyright (c) 2018 Marshall A. Greenblatt. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CEF_INCLUDE_WRAPPER_CEF_LIBRARY_LOADER_H_
#define CEF_INCLUDE_WRAPPER_CEF_LIBRARY_LOADER_H_
#pragma once
#include "include/base/cef_build.h"
#ifdef __cplusplus
#include <string>
#include "include/base/cef_macros.h"
extern "C" {
#endif // __cplusplus
///
// Load the CEF library at the specified |path|. Returns true (1) on
// success and false (0) on failure.
///
int cef_load_library(const char* path);
///
// Unload the CEF library that was previously loaded. Returns true (1)
// on success and false (0) on failure.
///
int cef_unload_library();
#ifdef __cplusplus
}
#if defined(OS_MACOSX)
///
// Scoped helper for loading and unloading the CEF framework library at
// runtime from the expected location in the app bundle. Loading at runtime
// instead of linking directly is a requirement of the macOS sandbox
// implementation.
//
// Example usage in the main process:
//
// int main(int argc, char* argv[]) {
// CefScopedLibraryLoader library_loader;
// if (!library_loader.LoadInMain())
// return 1;
//
// // Rest of the function here...
// }
//
// Example usage in the helper process:
//
// int main(int argc, char* argv[]) {
// CefScopedLibraryLoader library_loader;
// if (!library_loader.LoadInHelper())
// return 1;
//
// // Rest of the function here...
// }
///
class CefScopedLibraryLoader {
public:
CefScopedLibraryLoader();
~CefScopedLibraryLoader();
///
// Load the CEF framework in the main process from the expected app
// bundle location relative to the executable. Returns true if the
// load succeeds.
///
bool LoadInMain() { return Load(false); }
///
// Load the CEF framework in the helper process from the expected app
// bundle location relative to the executable. Returns true if the
// load succeeds.
///
bool LoadInHelper() { return Load(true); }
private:
bool Load(bool helper);
bool loaded_;
DISALLOW_COPY_AND_ASSIGN(CefScopedLibraryLoader);
};
#endif // defined(OS_MACOSX)
#endif // __cplusplus
#endif // CEF_INCLUDE_WRAPPER_CEF_LIBRARY_LOADER_H_

View File

@ -27,11 +27,13 @@ set(CEF_TARGET libcef_dll_wrapper)
'includes_capi',
'autogen_capi_includes',
'includes_wrapper',
'includes_wrapper_mac:MACOSX',
'includes_win:WINDOWS',
'includes_mac:MACOSX',
'includes_linux:LINUX',
'libcef_dll_wrapper_sources_base',
'libcef_dll_wrapper_sources_common',
'libcef_dll_wrapper_sources_mac:MACOSX',
'autogen_client_side',
],
}}

View File

@ -0,0 +1,77 @@
// Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "include/wrapper/cef_library_loader.h"
#include <libgen.h>
#include <mach-o/dyld.h>
#include <stdio.h>
#include <memory>
#include <sstream>
namespace {
const char kFrameworkPath[] =
"Chromium Embedded Framework.framework/Chromium Embedded Framework";
const char kPathFromHelperExe[] = "../../..";
const char kPathFromMainExe[] = "../Frameworks";
std::string GetFrameworkPath(bool helper) {
uint32_t exec_path_size = 0;
int rv = _NSGetExecutablePath(NULL, &exec_path_size);
if (rv != -1) {
return std::string();
}
std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
if (rv != 0) {
return std::string();
}
// Get the directory path of the executable.
const char* parent_dir = dirname(exec_path.get());
if (!parent_dir) {
return std::string();
}
// Append the relative path to the framework.
std::stringstream ss;
ss << parent_dir << "/" << (helper ? kPathFromHelperExe : kPathFromMainExe)
<< "/" << kFrameworkPath;
return ss.str();
}
} // namespace
CefScopedLibraryLoader::CefScopedLibraryLoader() : loaded_(false) {}
bool CefScopedLibraryLoader::Load(bool helper) {
if (loaded_) {
return false;
}
const std::string& framework_path = GetFrameworkPath(helper);
if (framework_path.empty()) {
fprintf(stderr, "App does not have the expected bundle structure.\n");
return false;
}
// Load the CEF framework library.
if (!cef_load_library(framework_path.c_str())) {
fprintf(stderr, "Failed to load the CEF framework.\n");
return false;
}
loaded_ = true;
return true;
}
CefScopedLibraryLoader::~CefScopedLibraryLoader() {
if (loaded_) {
// Unload the CEF framework library.
cef_unload_library();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -97,11 +97,11 @@ set(CEF_TARGET "cefclient")
if(OS_MACOSX)
set(CEF_HELPER_TARGET "cefclient_Helper")
set(CEF_HELPER_OUTPUT_NAME "cefclient Helper")
else()
# Logical target used to link the libcef library.
ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
endif()
# Logical target used to link the libcef library.
ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
# Determine the target output directory.
SET_CEF_TARGET_OUT_DIR()
@ -180,20 +180,17 @@ if(OS_MACOSX)
add_executable(${CEF_HELPER_TARGET} MACOSX_BUNDLE ${CEFCLIENT_HELPER_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_HELPER_TARGET})
add_dependencies(${CEF_HELPER_TARGET} libcef_dll_wrapper)
target_link_libraries(${CEF_HELPER_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
target_link_libraries(${CEF_HELPER_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
set_target_properties(${CEF_HELPER_TARGET} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/helper-Info.plist
OUTPUT_NAME ${CEF_HELPER_OUTPUT_NAME}
)
# Fix the framework rpath in the helper executable.
FIX_MACOSX_HELPER_FRAMEWORK_RPATH(${CEF_HELPER_TARGET})
# Main executable target.
add_executable(${CEF_TARGET} MACOSX_BUNDLE ${CEFCLIENT_RESOURCES_SRCS} ${CEFCLIENT_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
add_dependencies(${CEF_TARGET} libcef_dll_wrapper "${CEF_HELPER_TARGET}")
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS} "-framework OpenGL")
target_link_libraries(${CEF_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS} "-framework OpenGL")
set_target_properties(${CEF_TARGET} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/Info.plist
)
@ -213,9 +210,6 @@ if(OS_MACOSX)
VERBATIM
)
# Fix the framework rpath in the main executable.
FIX_MACOSX_MAIN_FRAMEWORK_RPATH(${CEF_TARGET})
# Manually process and copy over resource files.
# The Xcode generator can support this via the set_target_properties RESOURCE
# directive but that doesn't properly handle nested resource directories.

View File

@ -476,7 +476,13 @@ void RootWindowMac::CreateRootWindow(const CefBrowserSettings& settings,
NSRect screen_rect = [[NSScreen mainScreen] visibleFrame];
NSRect window_rect =
NSMakeRect(x, screen_rect.size.height - y, width, height);
window_ = [[UnderlayOpenGLHostingWindow alloc]
// The CEF framework library is loaded at runtime so we need to use this
// mechanism for retrieving the class.
Class window_class = NSClassFromString(@"UnderlayOpenGLHostingWindow");
CHECK(window_class);
window_ = [[window_class alloc]
initWithContentRect:window_rect
styleMask:(NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |

View File

@ -6,6 +6,7 @@
#import <Cocoa/Cocoa.h>
#include "include/cef_app.h"
#import "include/cef_application_mac.h"
#import "include/wrapper/cef_library_loader.h"
#include "tests/cefclient/browser/main_context_impl.h"
#include "tests/cefclient/browser/resource.h"
#include "tests/cefclient/browser/root_window.h"
@ -338,6 +339,12 @@ namespace client {
namespace {
int RunMain(int argc, char* argv[]) {
// Load the CEF framework library at runtime instead of linking directly
// as required by the macOS sandbox implementation.
CefScopedLibraryLoader library_loader;
if (!library_loader.LoadInMain())
return 1;
CefMainArgs main_args(argc, argv);
// Initialize the AutoRelease pool.
@ -403,7 +410,7 @@ int RunMain(int argc, char* argv[]) {
} // namespace
} // namespace client
// Program entry point function.
// Entry point function for the browser process.
int main(int argc, char* argv[]) {
return client::RunMain(argc, argv);
}

View File

@ -45,11 +45,11 @@ set(CEF_TARGET "cefsimple")
if(OS_MACOSX)
set(CEF_HELPER_TARGET "cefsimple_Helper")
set(CEF_HELPER_OUTPUT_NAME "cefsimple Helper")
else()
# Logical target used to link the libcef library.
ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
endif()
# Logical target used to link the libcef library.
ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
# Determine the target output directory.
SET_CEF_TARGET_OUT_DIR()
@ -95,20 +95,17 @@ if(OS_MACOSX)
add_executable(${CEF_HELPER_TARGET} MACOSX_BUNDLE ${CEFSIMPLE_HELPER_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_HELPER_TARGET})
add_dependencies(${CEF_HELPER_TARGET} libcef_dll_wrapper)
target_link_libraries(${CEF_HELPER_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
target_link_libraries(${CEF_HELPER_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
set_target_properties(${CEF_HELPER_TARGET} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/helper-Info.plist
OUTPUT_NAME ${CEF_HELPER_OUTPUT_NAME}
)
# Fix the framework rpath in the helper executable.
FIX_MACOSX_HELPER_FRAMEWORK_RPATH(${CEF_HELPER_TARGET})
# Main executable target.
add_executable(${CEF_TARGET} MACOSX_BUNDLE ${CEFSIMPLE_RESOURCES_SRCS} ${CEFSIMPLE_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
add_dependencies(${CEF_TARGET} libcef_dll_wrapper "${CEF_HELPER_TARGET}")
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper ${CEF_STANDARD_LIBS})
target_link_libraries(${CEF_TARGET} libcef_dll_wrapper ${CEF_STANDARD_LIBS})
set_target_properties(${CEF_TARGET} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/mac/Info.plist
)
@ -128,9 +125,6 @@ if(OS_MACOSX)
VERBATIM
)
# Fix the framework rpath in the main executable.
FIX_MACOSX_MAIN_FRAMEWORK_RPATH(${CEF_TARGET})
# Manually process and copy over resource files.
# The Xcode generator can support this via the set_target_properties RESOURCE
# directive but that doesn't properly handle nested resource directories.

View File

@ -7,6 +7,7 @@
#include "include/cef_application_mac.h"
#include "include/wrapper/cef_helpers.h"
#include "include/wrapper/cef_library_loader.h"
#include "tests/cefsimple/simple_app.h"
#include "tests/cefsimple/simple_handler.h"
@ -109,6 +110,12 @@
// Entry point function for the browser process.
int main(int argc, char* argv[]) {
// Load the CEF framework library at runtime instead of linking directly
// as required by the macOS sandbox implementation.
CefScopedLibraryLoader library_loader;
if (!library_loader.LoadInMain())
return 1;
// Provide CEF with command-line arguments.
CefMainArgs main_args(argc, argv);

View File

@ -3,9 +3,16 @@
// be found in the LICENSE file.
#include "include/cef_app.h"
#include "include/wrapper/cef_library_loader.h"
// Entry point function for sub-processes.
int main(int argc, char* argv[]) {
// 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);

View File

@ -59,11 +59,11 @@ set(CEF_TARGET "ceftests")
if(OS_MACOSX)
set(CEF_HELPER_TARGET "ceftests_Helper")
set(CEF_HELPER_OUTPUT_NAME "ceftests Helper")
else()
# Logical target used to link the libcef library.
ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
endif()
# Logical target used to link the libcef library.
ADD_LOGICAL_TARGET("libcef_lib" "${CEF_LIB_DEBUG}" "${CEF_LIB_RELEASE}")
# Determine the target output directory.
SET_CEF_TARGET_OUT_DIR()
@ -115,20 +115,17 @@ if(OS_MACOSX)
add_executable(${CEF_HELPER_TARGET} MACOSX_BUNDLE ${UNITTESTS_HELPER_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_HELPER_TARGET})
add_dependencies(${CEF_HELPER_TARGET} libcef_dll_wrapper cef_gtest)
target_link_libraries(${CEF_HELPER_TARGET} libcef_lib libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
target_link_libraries(${CEF_HELPER_TARGET} libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
set_target_properties(${CEF_HELPER_TARGET} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/helper-Info.plist
OUTPUT_NAME ${CEF_HELPER_OUTPUT_NAME}
)
# Fix the framework rpath in the helper executable.
FIX_MACOSX_HELPER_FRAMEWORK_RPATH(${CEF_HELPER_TARGET})
# Main executable target.
add_executable(${CEF_TARGET} MACOSX_BUNDLE ${UNITTESTS_RESOURCES_SRCS} ${UNITTESTS_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
add_dependencies(${CEF_TARGET} libcef_dll_wrapper cef_gtest "${CEF_HELPER_TARGET}")
target_link_libraries(${CEF_TARGET} libcef_lib libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
target_link_libraries(${CEF_TARGET} libcef_dll_wrapper cef_gtest ${CEF_STANDARD_LIBS})
set_target_properties(${CEF_TARGET} PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/resources/mac/Info.plist
)
@ -148,9 +145,6 @@ if(OS_MACOSX)
VERBATIM
)
# Fix the framework rpath in the main executable.
FIX_MACOSX_MAIN_FRAMEWORK_RPATH(${CEF_TARGET})
# Manually process and copy over resource files.
# The Xcode generator can support this via the set_target_properties RESOURCE
# directive but that doesn't properly handle nested resource directories.

View File

@ -29,6 +29,10 @@
#include "tests/shared/common/client_app_other.h"
#include "tests/shared/renderer/client_app_renderer.h"
#if defined(OS_MACOSX)
#include "include/wrapper/cef_library_loader.h"
#endif
#if defined(OS_WIN)
#include "include/cef_sandbox_win.h"
#endif
@ -93,6 +97,14 @@ int XIOErrorHandlerImpl(Display* display) {
} // namespace
int main(int argc, char* argv[]) {
#if defined(OS_MACOSX)
// Load the CEF framework library at runtime instead of linking directly
// as required by the macOS sandbox implementation.
CefScopedLibraryLoader library_loader;
if (!library_loader.LoadInMain())
return 1;
#endif
// Create the singleton test suite object.
CefTestSuite test_suite(argc, argv);

View File

@ -3,6 +3,7 @@
// be found in the LICENSE file.
#include "include/cef_app.h"
#import "include/wrapper/cef_library_loader.h"
#include "tests/shared/common/client_app_other.h"
#include "tests/shared/renderer/client_app_renderer.h"
@ -10,6 +11,12 @@
namespace client {
int RunMain(int argc, char* argv[]) {
// 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;
CefMainArgs main_args(argc, argv);
// Parse command-line arguments.
@ -30,7 +37,7 @@ int RunMain(int argc, char* argv[]) {
} // namespace client
// Process entry point.
// Entry point function for sub-processes.
int main(int argc, char* argv[]) {
return client::RunMain(argc, argv);
}

View File

@ -386,15 +386,18 @@ _simpletypes = {
}
def get_function_impls(content, ident):
def get_function_impls(content, ident, has_impl=True):
""" Retrieve the function parts from the specified contents as a set of
return value, name, arguments and body. Ident must occur somewhere in
the value.
"""
# extract the functions
p = re.compile(
'\n' + _cre_func + '\((.*?)\)([A-Za-z0-9_\s]{0,})' + '\{(.*?)\n\}',
re.MULTILINE | re.DOTALL)
find_regex = '\n' + _cre_func + '\((.*?)\)([A-Za-z0-9_\s]{0,})'
if has_impl:
find_regex += '\{(.*?)\n\}'
else:
find_regex += '(;)'
p = re.compile(find_regex, re.MULTILINE | re.DOTALL)
list = p.findall(content)
# build the function map with the function name as the key
@ -405,28 +408,31 @@ def get_function_impls(content, ident):
continue
# remove the identifier
retval = string.replace(retval, ident, '')
retval = string.strip(retval)
retval = retval.replace(ident, '')
retval = retval.strip()
# Normalize the delimiter.
retval = retval.replace('\n', ' ')
# retrieve the function name
parts = string.split(retval, ' ')
parts = retval.split(' ')
name = parts[-1]
del parts[-1]
retval = string.join(parts, ' ')
retval = ' '.join(parts)
# parse the arguments
args = []
for v in string.split(argval, ','):
v = string.strip(v)
for v in argval.split(','):
v = v.strip()
if len(v) > 0:
args.append(v)
result.append({
'retval': string.strip(retval),
'retval': retval.strip(),
'name': name,
'args': args,
'vfmod': string.strip(vfmod),
'body': body
'vfmod': vfmod.strip(),
'body': body if has_impl else '',
})
return result
@ -477,6 +483,10 @@ class obj_header:
""" Set the root directory. """
self.root_directory = root_directory
def get_root_directory(self):
""" Get the root directory. """
return self.root_directory
def add_directory(self, directory, excluded_files=[]):
""" Add all header files from the specified directory. """
files = get_files(os.path.join(directory, '*.h'))

View File

@ -920,6 +920,12 @@ elif platform == 'macosx':
# transfer include files
transfer_gypi_files(cef_dir, cef_paths2['includes_mac'], \
'include/', include_dir, options.quiet)
transfer_gypi_files(cef_dir, cef_paths2['includes_wrapper_mac'], \
'include/', include_dir, options.quiet)
# transfer libcef_dll_wrapper files
transfer_gypi_files(cef_dir, cef_paths2['libcef_dll_wrapper_sources_mac'], \
'libcef_dll/', libcef_dll_dir, options.quiet)
# transfer additional files, if any
transfer_files(cef_dir, script_dir, os.path.join(script_dir, 'distrib', 'mac'), \

View File

@ -0,0 +1,214 @@
# Copyright (c) 2018 The Chromium Embedded Framework Authors. All rights
# reserved. Use of this source code is governed by a BSD-style license that
# can be found in the LICENSE file.
from cef_parser import *
from file_util import *
import os
# Other headers that export C API functions.
OTHER_HEADERS = [
'cef_version.h',
'internal/cef_logging_internal.h',
'internal/cef_string_list.h',
'internal/cef_string_map.h',
'internal/cef_string_multimap.h',
'internal/cef_string_types.h',
'internal/cef_thread_internal.h',
'internal/cef_time.h',
'internal/cef_trace_event_internal.h',
]
def make_libcef_dll_dylib_impl_parts(name, retval, args):
# Split arguments into types and names.
arg_types = ''
arg_names = ''
for arg in args:
if len(arg_types) > 0:
arg_types += ', '
arg_names += ', '
pos = arg.rfind(' ')
arg_types += arg[0:pos]
arg_names += arg[pos + 1:]
typedef = 'typedef %s (*%s_ptr)(%s);\n' % (retval, name, arg_types)
declare = '%s_ptr %s;\n' % (name, name)
init = ' INIT_ENTRY(%s);' % name
impl = """NO_SANITIZE("cfi-icall") %s %s(%s) {
%sg_libcef_pointers.%s(%s);
}
""" % (retval, name, ', '.join(args), 'return '
if retval != 'void' else '', name, arg_names)
return (typedef, declare, init, impl)
def make_libcef_dll_dylib_impl_func(func):
name = func.get_capi_name()
parts = func.get_capi_parts([])
retval = parts['retval']
args = parts['args']
return make_libcef_dll_dylib_impl_parts(name, retval, args)
def make_libcef_dll_dylib_impl(header):
filenames = []
includes = []
ptr_typedef = ''
ptr_declare = ''
ptr_init = ''
ptr_impl = ''
# Include required headers for global functions.
for func in header.get_funcs():
typedef, declare, init, impl = make_libcef_dll_dylib_impl_func(func)
ptr_typedef += typedef
ptr_declare += declare
ptr_init += init
ptr_impl += impl
filename = func.get_file_name()
if not filename in filenames:
includes.append('#include "include/capi/%s"' % func.get_capi_file_name())
filenames.append(filename)
# Include required headers for static class functions.
allclasses = header.get_classes()
for cls in allclasses:
funcs = cls.get_static_funcs()
for func in funcs:
typedef, declare, init, impl = make_libcef_dll_dylib_impl_func(func)
ptr_typedef += typedef
ptr_declare += declare
ptr_init += init
ptr_impl += impl
if len(funcs) > 0:
filename = cls.get_file_name()
if not filename in filenames:
includes.append('#include "include/capi/%s"' % cls.get_capi_file_name())
filenames.append(filename)
# Parse other headers.
root_directory = header.get_root_directory()
for other in OTHER_HEADERS:
path = os.path.join(root_directory, other)
content = read_file(path)
funcs = get_function_impls(content, 'CEF_EXPORT', False)
for func in funcs:
typedef, declare, init, impl = make_libcef_dll_dylib_impl_parts(
func['name'], func['retval'], func['args'])
ptr_typedef += typedef
ptr_declare += declare
ptr_init += init
ptr_impl += impl
includes.append('#include "include/%s"' % other)
# Build the final output.
result = get_copyright() + """
#include <dlfcn.h>
#include <stdio.h>
""" + "\n".join(sorted(includes)) + """
#include "include/wrapper/cef_library_loader.h"
// GLOBAL WRAPPER FUNCTIONS - Do not edit by hand.
namespace {
void* g_libcef_handle = NULL;
void* libcef_get_ptr(const char* path, const char* name) {
void* ptr = dlsym(g_libcef_handle, name);
if (!ptr) {
fprintf(stderr, "dlsym %s: %s\\n", path, dlerror());
}
return ptr;
}
""" + ptr_typedef + """
struct libcef_pointers {
""" + ptr_declare + """
} g_libcef_pointers = {0};
#define INIT_ENTRY(name) \
g_libcef_pointers.name = (name##_ptr)libcef_get_ptr(path, #name); \
if (!g_libcef_pointers.name) { \
return 0; \
}
int libcef_init_pointers(const char* path) {
""" + ptr_init + """
return 1;
}
} // namespace
int cef_load_library(const char* path) {
if (g_libcef_handle)
return 0;
g_libcef_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST);
if (!g_libcef_handle) {
fprintf(stderr, "dlopen %s: %s\\n", path, dlerror());
return 0;
}
if (!libcef_init_pointers(path)) {
cef_unload_library();
return 0;
}
return 1;
}
int cef_unload_library() {
int result = 0;
if (g_libcef_handle) {
result = !dlclose(g_libcef_handle);
if (!result) {
fprintf(stderr, "dlclose: %s\\n", dlerror());
}
g_libcef_handle = NULL;
}
return result;
}
""" + ptr_impl
return result
def write_libcef_dll_dylib_impl(header, file):
newcontents = make_libcef_dll_dylib_impl(header)
return (file, newcontents)
# Test the module.
if __name__ == "__main__":
import sys
# Verify that the correct number of command-line arguments are provided.
if len(sys.argv) < 2:
sys.stderr.write('Usage: ' + sys.argv[0] + ' <cpp_header_dir>')
sys.exit()
cpp_header_dir = sys.argv[1]
# Create the header object. Should match the logic in translator.py.
header = obj_header()
header.set_root_directory(cpp_header_dir)
excluded_files = ['cef_application_mac.h', 'cef_version.h']
header.add_directory(cpp_header_dir, excluded_files)
header.add_directory(os.path.join(cpp_header_dir, 'test'))
header.add_directory(os.path.join(cpp_header_dir, 'views'))
# Dump the result to stdout.
sys.stdout.write(make_libcef_dll_dylib_impl(header))

View File

@ -13,6 +13,7 @@ from make_cpptoc_impl import *
from make_ctocpp_header import *
from make_ctocpp_impl import *
from make_gypi_file import *
from make_libcef_dll_dylib_impl import *
from make_views_stub_impl import *
from make_wrapper_types_header import *
from optparse import OptionParser
@ -80,6 +81,8 @@ cpptoc_dir = os.path.join(libcef_dll_dir, 'cpptoc')
ctocpp_dir = os.path.join(libcef_dll_dir, 'ctocpp')
gypi_file = os.path.join(root_dir, 'cef_paths.gypi')
views_stub_impl = os.path.join(libcef_dll_dir, 'views_stub.cc')
libcef_dll_dylib_impl = os.path.join(libcef_dll_dir, 'wrapper',
'libcef_dll_dylib.cc')
# make sure the header directory exists
if not path_exists(cpp_header_dir):
@ -139,7 +142,7 @@ def update_file(file, newcontents):
newcontents = newcontents.replace(hash_token, newhash, 1)
# Apply clang-format for C/C++ files.
if os.path.splitext(file)[1][1:] in ('cc', 'cpp', 'h'):
if os.path.splitext(file)[1][1:] in ('c', 'cc', 'cpp', 'h'):
result = clang_format(file, newcontents)
if result != None:
newcontents = result
@ -228,5 +231,10 @@ if not options.quiet:
sys.stdout.write('Generating ' + views_stub_impl + ' file...\n')
update_file(*write_views_stub_impl(header, views_stub_impl))
# output the libcef dll dylib file
if not options.quiet:
sys.stdout.write('Generating ' + libcef_dll_dylib_impl + ' file...\n')
update_file(*write_libcef_dll_dylib_impl(header, libcef_dll_dylib_impl))
if not options.quiet:
sys.stdout.write('Done - Wrote ' + str(writect) + ' files.\n')