macOS: Allow configuration of framework path (issue #1532)

This commit is contained in:
Marshall Greenblatt 2017-01-26 19:14:56 -05:00
parent 18ce862ad8
commit dda50912ed
9 changed files with 191 additions and 75 deletions

View File

@ -166,12 +166,23 @@ typedef struct _cef_settings_t {
/// ///
// The path to a separate executable that will be launched for sub-processes. // The path to a separate executable that will be launched for sub-processes.
// By default the browser process executable is used. See the comments on // If this value is empty on Windows or Linux then the main process executable
// CefExecuteProcess() for details. Also configurable using the // will be used. If this value is empty on macOS then a helper executable must
// "browser-subprocess-path" command-line switch. // exist at "Contents/Frameworks/<app> Helper.app/Contents/MacOS/<app> Helper"
// in the top-level app bundle. See the comments on CefExecuteProcess() for
// details. Also configurable using the "browser-subprocess-path" command-line
// switch.
/// ///
cef_string_t browser_subprocess_path; cef_string_t browser_subprocess_path;
///
// The path to the CEF framework directory on macOS. If this value is empty
// then the framework must exist at "Contents/Frameworks/Chromium Embedded
// Framework.framework" in the top-level app bundle. Also configurable using
// the "framework-dir-path" command-line switch.
///
cef_string_t framework_dir_path;
/// ///
// Set to true (1) to have the browser process message loop run in a separate // Set to true (1) to have the browser process message loop run in a separate
// thread. If false (0) than the CefDoMessageLoopWork() function must be // thread. If false (0) than the CefDoMessageLoopWork() function must be

View File

@ -620,6 +620,9 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches(
// associated values) if present in the browser command line. // associated values) if present in the browser command line.
static const char* const kSwitchNames[] = { static const char* const kSwitchNames[] = {
switches::kDisablePackLoading, switches::kDisablePackLoading,
#if defined(OS_MACOSX)
switches::kFrameworkDirPath,
#endif
switches::kLang, switches::kLang,
switches::kLocalesDirPath, switches::kLocalesDirPath,
switches::kLogFile, switches::kLogFile,

View File

@ -119,4 +119,9 @@ const char kEnablePreferenceTesting[] = "enable-preference-testing";
// Enable date-based expiration of built in network security information. // Enable date-based expiration of built in network security information.
const char kEnableNetSecurityExpiration[] = "enable-net-security-expiration"; const char kEnableNetSecurityExpiration[] = "enable-net-security-expiration";
#if defined(OS_MACOSX)
// Path to the framework directory.
const char kFrameworkDirPath[] = "framework-dir-path";
#endif
} // namespace switches } // namespace switches

View File

@ -8,6 +8,8 @@
#define CEF_LIBCEF_COMMON_CEF_SWITCHES_H_ #define CEF_LIBCEF_COMMON_CEF_SWITCHES_H_
#pragma once #pragma once
#include "build/build_config.h"
namespace switches { namespace switches {
extern const char kLogFile[]; extern const char kLogFile[];
@ -51,6 +53,10 @@ extern const char kPluginPolicy_Block[];
extern const char kEnablePreferenceTesting[]; extern const char kEnablePreferenceTesting[];
extern const char kEnableNetSecurityExpiration[]; extern const char kEnableNetSecurityExpiration[];
#if defined(OS_MACOSX)
extern const char kFrameworkDirPath[];
#endif
} // namespace switches } // namespace switches
#endif // CEF_LIBCEF_COMMON_CEF_SWITCHES_H_ #endif // CEF_LIBCEF_COMMON_CEF_SWITCHES_H_

View File

@ -20,7 +20,7 @@
#include "chrome/common/crash_keys.h" #include "chrome/common/crash_keys.h"
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
#include "base/mac/foundation_util.h" #include "libcef/common/util_mac.h"
#endif #endif
#if defined(OS_POSIX) #if defined(OS_POSIX)
@ -72,22 +72,20 @@ PathString GetCrashConfigPath() {
config_path += L"crash_reporter.cfg"; config_path += L"crash_reporter.cfg";
return config_path; return config_path;
#elif defined(OS_POSIX) #elif defined(OS_POSIX)
// Start with the path to the running executable.
base::FilePath config_path; base::FilePath config_path;
if (!PathService::Get(base::DIR_EXE, &config_path))
return PathString();
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
// Get the main app bundle path. // Start with the path to the main app Resources directory. May be empty if
config_path = base::mac::GetAppBundlePath(config_path); // not running in an app bundle.
if (config_path.empty()) config_path = util_mac::GetMainResourcesDirectory();
return PathString();
// Go into the Contents/Resources directory.
config_path = config_path.Append(FILE_PATH_LITERAL("Contents"))
.Append(FILE_PATH_LITERAL("Resources"));
#endif #endif
if (config_path.empty()) {
// Start with the path to the running executable.
if (!PathService::Get(base::DIR_EXE, &config_path))
return PathString();
}
return config_path.Append(FILE_PATH_LITERAL("crash_reporter.cfg")).value(); return config_path.Append(FILE_PATH_LITERAL("crash_reporter.cfg")).value();
#endif // defined(OS_POSIX) #endif // defined(OS_POSIX)
} }

View File

@ -70,57 +70,38 @@ namespace {
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
base::FilePath GetFrameworksPath() {
// Start out with the path to the running executable.
base::FilePath execPath;
PathService::Get(base::FILE_EXE, &execPath);
// Get the main bundle path.
base::FilePath bundlePath = base::mac::GetAppBundlePath(execPath);
// Go into the Contents/Frameworks directory.
return bundlePath.Append(FILE_PATH_LITERAL("Contents"))
.Append(FILE_PATH_LITERAL("Frameworks"));
}
// The framework bundle path is used for loading resources, libraries, etc.
base::FilePath GetFrameworkBundlePath() {
return GetFrameworksPath().Append(
FILE_PATH_LITERAL("Chromium Embedded Framework.framework"));
}
base::FilePath GetResourcesFilePath() { base::FilePath GetResourcesFilePath() {
return GetFrameworkBundlePath().Append(FILE_PATH_LITERAL("Resources")); return util_mac::GetFrameworkResourcesDirectory();
}
// Retrieve the name of the running executable.
std::string GetExecutableName() {
base::FilePath path;
PathService::Get(base::FILE_EXE, &path);
return path.BaseName().value();
} }
// Use a "~/Library/Logs/<app name>_debug.log" file where <app name> is the name // Use a "~/Library/Logs/<app name>_debug.log" file where <app name> is the name
// of the running executable. // of the running executable.
base::FilePath GetDefaultLogFile() { base::FilePath GetDefaultLogFile() {
std::string exe_name = util_mac::GetMainProcessPath().BaseName().value();
return base::mac::GetUserLibraryPath() return base::mac::GetUserLibraryPath()
.Append(FILE_PATH_LITERAL("Logs")) .Append(FILE_PATH_LITERAL("Logs"))
.Append(FILE_PATH_LITERAL(GetExecutableName() + "_debug.log")); .Append(FILE_PATH_LITERAL(exe_name + "_debug.log"));
} }
void OverrideFrameworkBundlePath() { void OverrideFrameworkBundlePath() {
base::mac::SetOverrideFrameworkBundlePath(GetFrameworkBundlePath()); base::FilePath framework_path = util_mac::GetFrameworkDirectory();
DCHECK(!framework_path.empty());
base::mac::SetOverrideFrameworkBundlePath(framework_path);
} }
void OverrideChildProcessPath() { void OverrideChildProcessPath() {
const std::string& exe_name = GetExecutableName(); // ChildProcessHost::GetChildPath() requires either kBrowserSubprocessPath or
base::FilePath helper_path = GetFrameworksPath() // CHILD_PROCESS_EXE but not both.
.Append(FILE_PATH_LITERAL(exe_name + " Helper.app")) if (base::CommandLine::ForCurrentProcess()->HasSwitch(
.Append(FILE_PATH_LITERAL("Contents")) switches::kBrowserSubprocessPath)) {
.Append(FILE_PATH_LITERAL("MacOS")) return;
.Append(FILE_PATH_LITERAL(exe_name + " Helper")); }
PathService::Override(content::CHILD_PROCESS_EXE, helper_path); base::FilePath child_process_path = util_mac::GetChildProcessPath();
DCHECK(!child_process_path.empty());
PathService::Override(content::CHILD_PROCESS_EXE, child_process_path);
} }
#else // !defined(OS_MACOSX) #else // !defined(OS_MACOSX)
@ -306,10 +287,6 @@ CefMainDelegate::~CefMainDelegate() {
} }
bool CefMainDelegate::BasicStartupComplete(int* exit_code) { bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
#if defined(OS_MACOSX)
OverrideFrameworkBundlePath();
#endif
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
std::string process_type = std::string process_type =
command_line->GetSwitchValueASCII(switches::kProcessType); command_line->GetSwitchValueASCII(switches::kProcessType);
@ -354,6 +331,15 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
} }
} }
#if defined(OS_MACOSX)
if (settings.framework_dir_path.length > 0) {
base::FilePath file_path =
base::FilePath(CefString(&settings.framework_dir_path));
if (!file_path.empty())
command_line->AppendSwitchPath(switches::kFrameworkDirPath, file_path);
}
#endif
if (no_sandbox) if (no_sandbox)
command_line->AppendSwitch(switches::kNoSandbox); command_line->AppendSwitch(switches::kNoSandbox);
@ -508,6 +494,10 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
content::SetContentClient(&content_client_); content::SetContentClient(&content_client_);
#if defined(OS_MACOSX)
OverrideFrameworkBundlePath();
#endif
return false; return false;
} }

View File

@ -1,6 +1,6 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
// Use of this source code is governed by a BSD-style license that can be // 2011 The Chromium Authors. All rights reserved. Use of this source code is
// found in the LICENSE file. // governed by a BSD-style license that can be found in the LICENSE file.
#ifndef CEF_LIBCEF_COMMON_UTIL_MAC_H_ #ifndef CEF_LIBCEF_COMMON_UTIL_MAC_H_
#define CEF_LIBCEF_COMMON_UTIL_MAC_H_ #define CEF_LIBCEF_COMMON_UTIL_MAC_H_
@ -12,8 +12,35 @@ class FilePath;
namespace util_mac { namespace util_mac {
// Returns the path to the NSLibraryDirectory (e.g. "~/Library").
bool GetLocalLibraryDirectory(base::FilePath* result); bool GetLocalLibraryDirectory(base::FilePath* result);
// Returns the path to the CEF framework directory inside the top-level app
// bundle (e.g. "myapp.app/Contents/Frameworks/Chromium Embedded
// Framework.framework"). May return an empty value if not running in an app
// bundle.
base::FilePath GetFrameworkDirectory();
// Returns the path to the Resources directory inside the CEF framework
// directory (e.g. "myapp.app/Contents/Frameworks/Chromium Embedded
// Framework.framework/Resources"). May return an empty value if not running in
// an app bundle.
base::FilePath GetFrameworkResourcesDirectory();
// Returns the path to the main (running) process executable (e.g.
// "myapp.app/Contents/MacOS/myapp").
base::FilePath GetMainProcessPath();
// Returns the path to the Resources directory inside the top-level app bundle
// (e.g. "myapp.app/Contents/Resources"). May return an empty value if not
// running in an app bundle.
base::FilePath GetMainResourcesDirectory();
// Returns the path to the child process executable (e.g. "myapp.app/
// Contents/Frameworks/myapp Helper.app/Contents/MacOS/myapp Helper"). May
// return an empty value if not running in an app bundle.
base::FilePath GetChildProcessPath();
} // namespace util_mac } // namespace util_mac
#endif // CEF_LIBCEF_COMMON_UTIL_MAC_H_ #endif // CEF_LIBCEF_COMMON_UTIL_MAC_H_

View File

@ -1,15 +1,92 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
// Use of this source code is governed by a BSD-style license that can be // 2011 The Chromium Authors. All rights reserved. Use of this source code is
// found in the LICENSE file. // governed by a BSD-style license that can be found in the LICENSE file.
#include "libcef/common/util_mac.h" #include "libcef/common/util_mac.h"
#include "libcef/common/cef_switches.h"
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#include "base/path_service.h"
namespace util_mac { namespace util_mac {
namespace {
// Returns the path to the top-level app bundle that contains the main process
// executable.
base::FilePath GetMainBundlePath() {
return base::mac::GetAppBundlePath(GetMainProcessPath());
}
// Returns the path to the Frameworks directory inside the top-level app bundle.
base::FilePath GetFrameworksPath() {
base::FilePath bundle_path = GetMainBundlePath();
if (bundle_path.empty())
return base::FilePath();
return bundle_path.Append(FILE_PATH_LITERAL("Contents"))
.Append(FILE_PATH_LITERAL("Frameworks"));
}
} // namespace
bool GetLocalLibraryDirectory(base::FilePath* result) { bool GetLocalLibraryDirectory(base::FilePath* result) {
return base::mac::GetLocalDirectory(NSLibraryDirectory, result); return base::mac::GetLocalDirectory(NSLibraryDirectory, result);
} }
base::FilePath GetFrameworkDirectory() {
base::FilePath frameworks_path =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
switches::kFrameworkDirPath);
if (!frameworks_path.empty())
return frameworks_path;
frameworks_path = GetFrameworksPath();
if (frameworks_path.empty())
return base::FilePath();
return frameworks_path.Append(
FILE_PATH_LITERAL("Chromium Embedded Framework.framework"));
}
base::FilePath GetFrameworkResourcesDirectory() {
base::FilePath frameworks_path = GetFrameworkDirectory();
if (frameworks_path.empty())
return base::FilePath();
return frameworks_path.Append(FILE_PATH_LITERAL("Resources"));
}
base::FilePath GetMainProcessPath() {
base::FilePath path;
PathService::Get(base::FILE_EXE, &path);
DCHECK(!path.empty());
return path;
}
base::FilePath GetMainResourcesDirectory() {
base::FilePath bundle_path = GetMainBundlePath();
if (bundle_path.empty())
return base::FilePath();
return bundle_path.Append(FILE_PATH_LITERAL("Contents"))
.Append(FILE_PATH_LITERAL("Resources"));
}
base::FilePath GetChildProcessPath() {
base::FilePath frameworks_path = GetFrameworksPath();
if (frameworks_path.empty())
return base::FilePath();
std::string exe_name = GetMainProcessPath().BaseName().value();
return frameworks_path.Append(FILE_PATH_LITERAL(exe_name + " Helper.app"))
.Append(FILE_PATH_LITERAL("Contents"))
.Append(FILE_PATH_LITERAL("MacOS"))
.Append(FILE_PATH_LITERAL(exe_name + " Helper"));
}
} // namespace util_mac } // namespace util_mac

View File

@ -27,27 +27,26 @@ bool AmIBundled() {
} // namespace } // namespace
// Implementation adapted from Chromium's base/base_path_mac.mm
bool GetResourceDir(std::string& dir) { bool GetResourceDir(std::string& dir) {
// Implementation adapted from Chromium's base/base_path_mac.mm // Retrieve the executable directory.
if (AmIBundled()) { uint32_t pathSize = 0;
// Retrieve the executable directory. _NSGetExecutablePath(NULL, &pathSize);
uint32_t pathSize = 0; if (pathSize > 0) {
_NSGetExecutablePath(NULL, &pathSize); dir.resize(pathSize);
if (pathSize > 0) { _NSGetExecutablePath(const_cast<char*>(dir.c_str()), &pathSize);
dir.resize(pathSize); }
_NSGetExecutablePath(const_cast<char*>(dir.c_str()), &pathSize);
}
// Trim executable name up to the last separator if (AmIBundled()) {
// Trim executable name up to the last separator.
std::string::size_type last_separator = dir.find_last_of("/"); std::string::size_type last_separator = dir.find_last_of("/");
dir.resize(last_separator); dir.resize(last_separator);
dir.append("/../Resources"); dir.append("/../Resources");
return true; return true;
} else {
// TODO: Provide unbundled path
NOTIMPLEMENTED();
return false;
} }
dir.append("/Resources");
return true;
} }
} // namespace client } // namespace client