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.
// By default the browser process executable is used. See the comments on
// CefExecuteProcess() for details. Also configurable using the
// "browser-subprocess-path" command-line switch.
// If this value is empty on Windows or Linux then the main process executable
// will be used. If this value is empty on macOS then a helper executable must
// 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;
///
// 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
// 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.
static const char* const kSwitchNames[] = {
switches::kDisablePackLoading,
#if defined(OS_MACOSX)
switches::kFrameworkDirPath,
#endif
switches::kLang,
switches::kLocalesDirPath,
switches::kLogFile,

View File

@ -119,4 +119,9 @@ const char kEnablePreferenceTesting[] = "enable-preference-testing";
// Enable date-based expiration of built in network security information.
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

View File

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

View File

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

View File

@ -70,57 +70,38 @@ namespace {
#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() {
return GetFrameworkBundlePath().Append(FILE_PATH_LITERAL("Resources"));
}
// Retrieve the name of the running executable.
std::string GetExecutableName() {
base::FilePath path;
PathService::Get(base::FILE_EXE, &path);
return path.BaseName().value();
return util_mac::GetFrameworkResourcesDirectory();
}
// Use a "~/Library/Logs/<app name>_debug.log" file where <app name> is the name
// of the running executable.
base::FilePath GetDefaultLogFile() {
std::string exe_name = util_mac::GetMainProcessPath().BaseName().value();
return base::mac::GetUserLibraryPath()
.Append(FILE_PATH_LITERAL("Logs"))
.Append(FILE_PATH_LITERAL(GetExecutableName() + "_debug.log"));
.Append(FILE_PATH_LITERAL(exe_name + "_debug.log"));
}
void OverrideFrameworkBundlePath() {
base::mac::SetOverrideFrameworkBundlePath(GetFrameworkBundlePath());
base::FilePath framework_path = util_mac::GetFrameworkDirectory();
DCHECK(!framework_path.empty());
base::mac::SetOverrideFrameworkBundlePath(framework_path);
}
void OverrideChildProcessPath() {
const std::string& exe_name = GetExecutableName();
base::FilePath helper_path = GetFrameworksPath()
.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"));
// ChildProcessHost::GetChildPath() requires either kBrowserSubprocessPath or
// CHILD_PROCESS_EXE but not both.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kBrowserSubprocessPath)) {
return;
}
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)
@ -306,10 +287,6 @@ CefMainDelegate::~CefMainDelegate() {
}
bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
#if defined(OS_MACOSX)
OverrideFrameworkBundlePath();
#endif
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
std::string process_type =
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)
command_line->AppendSwitch(switches::kNoSandbox);
@ -508,6 +494,10 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
content::SetContentClient(&content_client_);
#if defined(OS_MACOSX)
OverrideFrameworkBundlePath();
#endif
return false;
}

View File

@ -1,6 +1,6 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
// 2011 The Chromium Authors. All rights reserved. Use of this source code is
// governed by a BSD-style license that can be found in the LICENSE file.
#ifndef CEF_LIBCEF_COMMON_UTIL_MAC_H_
#define CEF_LIBCEF_COMMON_UTIL_MAC_H_
@ -12,8 +12,35 @@ class FilePath;
namespace util_mac {
// Returns the path to the NSLibraryDirectory (e.g. "~/Library").
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
#endif // CEF_LIBCEF_COMMON_UTIL_MAC_H_

View File

@ -1,15 +1,92 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
// 2011 The Chromium 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 "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/path_service.h"
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) {
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

View File

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