# Copyright (c) 2016 CEF Python, see the Authors file. All rights reserved.
"""
Prepares CEF binaries and libraries for work with the build.py tool.
Option 1 is to build CEF from sources with the CEF Python patches applied
using the --build-cef flag.
Option 2 is to use CEF binaries from Spotify Automated Builds using
the --prebuilt-cef flag. In such case check the cefpython/src/version/
directory to know which version of CEF to download from Spotify:
http://opensource.spotify.com/cefbuilds/index.html
Download and extract it so that for example you have such a directory:
cefpython/build/cef_binary_3.2883.1553.g80bd606_windows32/ .
This tool generates CEF binaries and libraries that are ready for work
with cefpython, with the build.py script. When automate.py tool completes
job you should see a new subdirectory in the build/ directory, for example:
cefpython/build/cef55_3.2883.1553.g80bd606_win32/ .
Usage:
automate.py (--prebuilt-cef | --build-cef)
[--fast-build FAST_BUILD]
[--force-chromium-update FORCE_CHROMIUM_UPDATE]
[--no-cef-update NO_CEF_UPDATE]
[--cef-branch BRANCH] [--cef-commit COMMIT]
[--build-dir BUILD_DIR] [--cef-build-dir CEF_BUIL_DDIR]
[--ninja-jobs JOBS] [--gyp-generators GENERATORS]
[--gyp-msvs-version MSVS]
automate.py (-h | --help) [type -h to show full description for options]
Options:
-h --help Show this help message.
--prebuilt-cef Whether to use prebuilt CEF binaries. Prebuilt
binaries for Linux are built on Ubuntu.
--build-cef Whether to build CEF from sources with the
cefpython patches applied.
--fast-build Fast build with is_official_build=False
--force-chromium-update Force Chromium update (gclient sync etc).
--no-cef-update Do not update CEF sources (by default both cef/
directories are deleted on every run).
--cef-branch= CEF branch. Defaults to CHROME_VERSION_BUILD from
"src/version/cef_version_{platform}.h".
--cef-commit= CEF revision. Defaults to CEF_COMMIT_HASH from
"src/version/cef_version_{platform}.h".
--build-dir= Build directory.
--cef-build-dir= CEF build directory. By default same
as --build-dir.
--ninja-jobs= How many CEF jobs to run in parallel. To speed up
building set it to number of cores in your CPU.
By default set to cpu_count / 2.
--gyp-generators= Set GYP_GENERATORS [default: ninja].
--gyp-msvs-version= Set GYP_MSVS_VERSION.
"""
from common import *
import os
import sys
import shlex
import subprocess
import platform
import docopt
import stat
import glob
import shutil
import multiprocessing
CEF_GIT_URL = "https://bitbucket.org/chromiumembedded/cef.git"
class Options(object):
"""Options from command-line and internal options."""
# From command-line
prebuilt_cef = False
build_cef = False
fast_build = False
force_chromium_update = False
no_cef_update = False
cef_branch = ""
cef_commit = ""
cef_version = ""
build_dir = ""
cef_build_dir = ""
ninja_jobs = None
gyp_generators = "ninja" # Even though CEF uses now GN, still some GYP
gyp_msvs_version = "" # env variables are being used.
# Internal options
depot_tools_dir = ""
tools_dir = ""
cefpython_dir = ""
binary_distrib = ""
release_build = True
build_type = "" # Will be set according to "release_build" value
cef_binary = ""
build_cefclient_dir = ""
build_wrapper_mt_dir = ""
build_wrapper_md_dir = ""
def main():
"""Main entry point."""
if not ((2, 7) <= sys.version_info < (2, 8)):
print("ERROR: to run this tool you need Python 2.7, as upstream")
print(" automate-git.py works only with that version.")
sys.exit(1)
if len(sys.argv) <= 1:
print(__doc__)
sys.exit(1)
setup_options(docopt.docopt(__doc__))
if Options.build_cef:
build_cef()
# Build cefclient, cefsimple, ceftests, libcef_dll_wrapper
build_cef_projects()
create_prebuilt_binaries()
elif Options.prebuilt_cef:
prebuilt_cef()
def setup_options(docopt_args):
"""Setup options from cmd-line and internal options."""
# Populate Options using command line arguments
for key in docopt_args:
value = docopt_args[key]
key2 = key.replace("--", "").replace("-", "_")
if hasattr(Options, key2) and value is not None:
setattr(Options, key2, value)
Options.tools_dir = os.path.dirname(os.path.realpath(__file__))
Options.cefpython_dir = os.path.dirname(Options.tools_dir)
# If --cef-branch is specified will use latest CEF commit from that
# branch. Otherwise get cef branch/commit from src/version/.
if not Options.cef_branch:
# Use branch/commit from the src/version/cef_version_*.h file
Options.cef_branch = get_cefpython_version()["CHROME_VERSION_BUILD"]
Options.cef_commit = get_cefpython_version()["CEF_COMMIT_HASH"]
Options.cef_version = get_cefpython_version()["CEF_VERSION"]
# --gyp-msvs-version
if not Options.gyp_msvs_version:
if int(Options.cef_branch) >= 2704:
Options.gyp_msvs_version = "2015"
else:
Options.gyp_msvs_version = "2013"
# --build-dir
if Options.build_dir:
Options.build_dir = os.path.realpath(Options.build_dir)
else:
Options.build_dir = os.path.join(Options.cefpython_dir, "build")
if " " in Options.build_dir:
print("[automate.py] ERROR: Build dir cannot contain spaces")
print(">> " + Options.build_dir)
sys.exit(1)
if not os.path.exists(Options.build_dir):
os.makedirs(Options.build_dir)
# --cef-build-dir
if Options.cef_build_dir:
Options.cef_build_dir = os.path.realpath(Options.cef_build_dir)
else:
Options.cef_build_dir = Options.build_dir
if " " in Options.cef_build_dir:
print("[automate.py] ERROR: CEF build dir cannot contain spaces")
print(">> " + Options.cef_build_dir)
sys.exit(1)
if not os.path.exists(Options.cef_build_dir):
os.makedirs(Options.cef_build_dir)
# --depot-tools-dir
Options.depot_tools_dir = os.path.join(Options.cef_build_dir,
"depot_tools")
# binary_distrib
Options.binary_distrib = os.path.join(Options.cef_build_dir, "chromium",
"src", "cef", "binary_distrib")
# build_type
Options.build_type = "Release" if Options.release_build else "Debug"
# ninja_jobs
# cpu_count() returns number of CPU threads, not CPU cores.
# On i5 with 2 cores and 4 cpu threads the default of 4 ninja
# jobs slows down computer significantly.
if not Options.ninja_jobs:
Options.ninja_jobs = int(multiprocessing.cpu_count() / 2)
if Options.ninja_jobs < 1:
Options.ninja_jobs = 1
def build_cef():
"""Build CEF from sources."""
# cef/ repo
create_cef_directories()
# Delete binary_distrib
if os.path.exists(Options.binary_distrib):
rmdir(Options.binary_distrib)
# Run automate-git.py
run_automate_git()
print("[automate.py] Binary distrib created in %s"
% Options.binary_distrib)
def prebuilt_cef():
"""Use prebuilt binaries."""
# TODO: Option to download CEF prebuilt binaries from GitHub Releases,
# eg. tag 'upstream-cef47'.
# Find cef_binary directory in the build directory
if Options.cef_version:
cef_binary = os.path.join(Options.build_dir,
"cef_binary_{cef_version}_*{sep}"
.format(cef_version=Options.cef_version,
sep=os.sep))
else:
cef_binary = os.path.join(Options.build_dir,
"cef_binary_3.{cef_branch}.*{sep}"
.format(cef_branch=Options.cef_branch,
sep=os.sep))
dirs = glob.glob(cef_binary)
if len(dirs) == 1:
Options.cef_binary = dirs[0]
else:
print("ERROR: Could not find prebuilt binaries in the build dir.")
print(" Eg. cef_binary_3.2883.1553.g80bd606_windows32/")
sys.exit(1)
build_cef_projects()
create_prebuilt_binaries()
def create_cef_directories():
"""Create cef/ directories in cef_build_dir/ and in chromium/src/ ."""
if Options.no_cef_update:
return
cef_dir = os.path.join(Options.cef_build_dir, "cef")
src_dir = os.path.join(Options.cef_build_dir, "chromium", "src")
cef_dir2 = os.path.join(src_dir, "cef")
# Clone cef repo and checkout branch
if os.path.exists(cef_dir):
rmdir(cef_dir)
run_git("clone -b %s %s cef" % (Options.cef_branch, CEF_GIT_URL),
Options.cef_build_dir)
if Options.cef_commit:
run_git("checkout %s" % Options.cef_commit, cef_dir)
# Update cef patches
update_cef_patches()
# Copy cef/ to chromium/src/ but only if chromium/src/ exists,
# but don't copy it and delete if exists when --force-chromium-update
# flag is passed, chromium throws error about unstaged changes.
if os.path.exists(src_dir):
if os.path.exists(cef_dir2):
rmdir(cef_dir2)
if not Options.force_chromium_update:
shutil.copytree(cef_dir, cef_dir2)
def update_cef_patches():
"""Update cef/patch/ directory with CEF Python patches.
Issue73 is applied in getenv() by setting appropriate env var.
Note that this modifies only cef_build_dir/cef/ directory. If the
build was run previously then there is a copy of the cef/ directory
in the cef_build_dir/chromium/ directory which is not being updated.
"""
print("[automate.py] Updating CEF patches with CEF Python patches")
cef_dir = os.path.join(Options.cef_build_dir, "cef")
cef_patch_dir = os.path.join(cef_dir, "patch")
cef_patches_dir = os.path.join(cef_patch_dir, "patches")
# Copy src/patches/*.patch to cef/patch/patches/
cefpython_patches_dir = os.path.join(Options.cefpython_dir, "patches")
cefpython_patches = glob.glob(os.path.join(cefpython_patches_dir,
"*.patch"))
for file_ in cefpython_patches:
print("[automate.py] Copying %s to %s"
% (os.path.basename(file_), cef_patches_dir))
shutil.copy(file_, cef_patches_dir)
# Append cefpython/patches/patch.py to cef/patch/patch.cfg
cef_patch_cfg = os.path.join(cef_patch_dir, "patch.cfg")
print("[automate.py] Overwriting %s" % cef_patch_cfg)
with open(cef_patch_cfg, "rb") as fp:
cef_patch_cfg_contents = fp.read()
cef_patch_cfg_contents += "\n"
cefpython_patch_cfg = os.path.join(cefpython_patches_dir, "patch.py")
with open(cefpython_patch_cfg, "rb") as fp:
cefpython_patch_cfg_contents = fp.read()
with open(cef_patch_cfg, "wb") as fp:
cef_patch_cfg_contents = cef_patch_cfg_contents.replace("\r\n", "\n")
cefpython_patch_cfg_contents = cefpython_patch_cfg_contents.replace(
"\r\n", "\n")
new_contents = cef_patch_cfg_contents + cefpython_patch_cfg_contents
fp.write(new_contents)
def build_cef_projects():
"""Build cefclient, cefsimple, ceftests, libcef_dll_wrapper."""
print("[automate.py] Building cef projects...")
fix_cef_include_files()
# Find cef_binary directory
if not Options.cef_binary:
if platform.system() == "Windows":
files = glob.glob(os.path.join(Options.binary_distrib,
"cef_binary_*_symbols"))
assert len(files) == 1, ("More than one dir with release"
" symbols found")
symbols = files[0]
if Options.release_build:
cef_binary = symbols.replace("_release_symbols", "")
else:
cef_binary = symbols.replace("_debug_symbols", "")
assert "symbols" not in os.path.basename(cef_binary)
else:
files = glob.glob(os.path.join(Options.binary_distrib,
"cef_binary_*_"+OS_POSTFIX2))
assert len(files) == 1, "Error finding binary distrib"
cef_binary = files[0]
assert os.path.exists(cef_binary)
Options.cef_binary = cef_binary
# Set build directory
Options.build_cefclient_dir = os.path.join(Options.cef_binary,
"build_cefclient")
print("[automate.py] Creating build_cefclient dir in cef_binary dir")
# Check whether already built
already_built = False
if build_cefclient_succeeded():
already_built = True
elif os.path.exists(Options.build_cefclient_dir):
# Last build failed, clean directory
assert Options.build_cefclient_dir
shutil.rmtree(Options.build_cefclient_dir)
os.makedirs(Options.build_cefclient_dir)
else:
os.makedirs(Options.build_cefclient_dir)
# Build cefclient, cefsimple, ceftests
if already_built:
print("[automate.py] Already built: cefclient, cefsimple, ceftests")
else:
print("[automate.py] Build cefclient, cefsimple, ceftests")
# Cmake
command = prepare_build_command()
command.extend(["cmake", "-G", "Ninja"])
command.append("-DCMAKE_BUILD_TYPE="+Options.build_type)
if MAC:
command.append("-DPROJECT_ARCH=x86_64")
command.append("..")
run_command(command, Options.build_cefclient_dir)
print("[automate.py] OK")
# Ninja
command = prepare_build_command()
command.extend(["ninja", "cefclient", "cefsimple", "ceftests"])
run_command(command, Options.build_cefclient_dir)
print("[automate.py] OK")
assert build_cefclient_succeeded()
# Build libcef_dll_wrapper libs
if platform.system() == "Windows":
build_wrapper_windows()
def build_wrapper_windows():
# When building library cmake variables file is being modified
# for the /MD build. If the build fails and variables aren't
# restored then the next /MT build would be broken. Make sure
# that original contents of cmake variables files is always
# restored.
fix_cmake_variables_for_md_library(try_undo=True)
# Command to build libcef_dll_wrapper
cmake_wrapper = prepare_build_command(build_lib=True)
cmake_wrapper.extend(["cmake", "-G", "Ninja",
"-DCMAKE_BUILD_TYPE="+Options.build_type, ".."])
# Set build directory for /MT lib.
Options.build_wrapper_mt_dir = os.path.join(Options.cef_binary,
"build_wrapper_mt")
# Check whether already built
mt_already_built = False
if build_wrapper_mt_succeeded():
mt_already_built = True
elif os.path.exists(Options.build_wrapper_mt_dir):
# Last build failed, clean directory
assert Options.build_wrapper_mt_dir
shutil.rmtree(Options.build_wrapper_mt_dir)
os.makedirs(Options.build_wrapper_mt_dir)
else:
os.makedirs(Options.build_wrapper_mt_dir)
# Build /MT lib.
if mt_already_built:
print("[automate.py] Already built: libcef_dll_wrapper /MT")
else:
print("[automate.py] Build libcef_dll_wrapper /MT")
old_gyp_msvs_version = Options.gyp_msvs_version
Options.gyp_msvs_version = get_msvs_for_python()
# Cmake
run_command(cmake_wrapper, Options.build_wrapper_mt_dir)
Options.gyp_msvs_version = old_gyp_msvs_version
print("[automate.py] cmake OK")
# Ninja
ninja_wrapper = prepare_build_command(build_lib=True)
ninja_wrapper.extend(["ninja", "libcef_dll_wrapper"])
run_command(ninja_wrapper, Options.build_wrapper_mt_dir)
print("[automate.py] ninja OK")
assert build_wrapper_mt_succeeded()
# Set build directory for /MD lib.
Options.build_wrapper_md_dir = os.path.join(Options.cef_binary,
"build_wrapper_md")
# Check whether already built
md_already_built = False
if build_wrapper_md_succeeded():
md_already_built = True
elif os.path.exists(Options.build_wrapper_md_dir):
# Last build failed, clean directory
assert Options.build_wrapper_md_dir
shutil.rmtree(Options.build_wrapper_md_dir)
os.makedirs(Options.build_wrapper_md_dir)
else:
os.makedirs(Options.build_wrapper_md_dir)
# Build /MD lib.
if md_already_built:
print("[automate.py] Already built: libcef_dll_wrapper /MD")
else:
print("[automate.py] Build libcef_dll_wrapper /MD")
old_gyp_msvs_version = Options.gyp_msvs_version
Options.gyp_msvs_version = get_msvs_for_python()
# Fix cmake variables
# Cmake
fix_cmake_variables_for_md_library()
run_command(cmake_wrapper, Options.build_wrapper_md_dir)
Options.gyp_msvs_version = old_gyp_msvs_version
fix_cmake_variables_for_md_library(undo=True)
print("[automate.py] cmake OK")
# Ninja
ninja_wrapper = prepare_build_command(build_lib=True)
ninja_wrapper.extend(["ninja", "libcef_dll_wrapper"])
run_command(ninja_wrapper, Options.build_wrapper_md_dir)
print("[automate.py] ninja OK")
assert build_wrapper_md_succeeded()
def fix_cmake_variables_for_md_library(undo=False, try_undo=False):
"""Fix cmake variables or undo it. The try_undo param is
for a case when want to be sure that the file wasn't modified,
for example in case the last build failed."""
# Replace /MT with /MD /wd4275 in cef/cmake/cef_variables.cmake
# Warnings are treated as errors so this needs to be ignored:
# >> warning C4275: non dll-interface class 'stdext::exception'
# >> used as base for dll-interface class 'std::bad_cast'
# This warning occurs only in VS2008, in VS2013 not.
# This replacements must be unique for the undo operation
# to be reliable.
mt_find = r"/MT "
mt_replace = r"/MD /wd4275 "
mtd_find = r"/MTd "
mtd_replace = r"/MDd /wd4275 "
cmake_variables = os.path.join(Options.cef_binary, "cmake",
"cef_variables.cmake")
with open(cmake_variables, "rb") as fp:
contents = fp.read()
if try_undo:
matches1 = re.findall(re.escape(mt_replace), contents)
matches2 = re.findall(re.escape(mtd_replace), contents)
if len(matches1) or len(matches2):
undo = True
else:
return
if undo:
(contents, count) = re.subn(re.escape(mt_replace), mt_find,
contents)
assert count == 2
(contents, count) = re.subn(re.escape(mtd_replace), mtd_find,
contents)
assert count == 1
else:
(contents, count) = re.subn(re.escape(mt_find), mt_replace,
contents)
assert count == 2
(contents, count) = re.subn(re.escape(mtd_find), mtd_replace,
contents)
assert count == 1
with open(cmake_variables, "wb") as fp:
fp.write(contents)
def build_cefclient_succeeded():
"""Whether building cefclient/cefsimple/ceftests succeeded."""
assert Options.build_cefclient_dir
cefclient_exe = "cefclient.exe" if WINDOWS else "cefclient"
return os.path.exists(os.path.join(Options.build_cefclient_dir,
"tests",
"cefclient",
Options.build_type,
cefclient_exe))
def build_wrapper_mt_succeeded():
"""Whether building /MT library succeeded (Windows-only)."""
assert Options.build_wrapper_mt_dir
return os.path.exists(os.path.join(Options.build_wrapper_mt_dir,
"libcef_dll_wrapper",
"libcef_dll_wrapper.lib"))
def build_wrapper_md_succeeded():
"""Whether building /MD library succeeded (Windows-only)."""
assert Options.build_wrapper_md_dir
return os.path.exists(os.path.join(Options.build_wrapper_md_dir,
"libcef_dll_wrapper",
"libcef_dll_wrapper.lib"))
def prepare_build_command(build_lib=False):
"""On Windows VS env variables must be set up by calling vcvarsall.bat"""
command = list()
if platform.system() == "Windows":
if build_lib:
msvs = get_msvs_for_python()
command.append(globals()["VS"+msvs+"_VCVARS"])
else:
if int(Options.cef_branch) >= 2704:
command.append(VS2015_VCVARS)
else:
command.append(VS2013_VCVARS)
command.append("&&")
return command
def fix_cef_include_files():
"""Fixes to CEF include header files for eg. VS2008 on Windows."""
if platform.system() == "Windows" and get_msvs_for_python() == "2008":
print("[automate.py] Fixing CEF include/ files")
# cef_types_wrappers.h
cef_types_wrappers = os.path.join(Options.cef_binary, "include",
"internal", "cef_types_wrappers.h")
with open(cef_types_wrappers, "rb") as fp:
contents = fp.read()
# error C2059: syntax error : '{'
contents = contents.replace("s->range = {0, 0};",
"s->range.from = 0; s->range.to = 0;")
with open(cef_types_wrappers, "wb") as fp:
fp.write(contents)
def create_prebuilt_binaries():
"""After building copy binaries/libs to build/cef_xxxx/. """
# Directories
src = Options.cef_binary
version_header = os.path.join(src, "include", "cef_version.h")
dst = get_prebuilt_name(version_header)
dst = os.path.join(Options.build_dir, dst)
rmdir(dst)
os.makedirs(dst)
bindir = os.path.join(dst, "bin")
libdir = os.path.join(dst, "lib")
os.makedirs(bindir)
os.makedirs(libdir)
# Copy Release/Debug and Resources
cpdir(os.path.join(src, Options.build_type), bindir)
cpdir(os.path.join(src, "Resources"), bindir)
# Copy cefclient, cefsimple, ceftests
# cefclient
cefclient = os.path.join(
src,
"build_cefclient", "tests", "cefclient",
Options.build_type,
"cefclient")
if platform.system() != "Windows":
# On Windows resources/*.html files are embedded inside exe
cefclient_files = os.path.join(
src,
"build_cefclient", "tests", "cefclient",
Options.build_type,
"cefclient_files")
cpdir(cefclient_files, os.path.join(bindir, "cefclient_files"))
# cefsimple
cefsimple = os.path.join(
src,
"build_cefclient", "tests", "cefsimple",
Options.build_type,
"cefsimple")
# ceftests
ceftests = os.path.join(
src,
"build_cefclient", "tests", "ceftests",
Options.build_type,
"ceftests")
if platform.system() != "Windows":
# On Windows resources/*.html files are embedded inside exe
ceftests_files = os.path.join(
src,
"build_cefclient", "tests", "ceftests",
Options.build_type,
"ceftests_files")
cpdir(ceftests_files, os.path.join(bindir, "ceftests_files"))
if platform.system() == "Windows":
cefclient += ".exe"
cefsimple += ".exe"
ceftests += ".exe"
shutil.copy(cefclient, bindir)
shutil.copy(cefsimple, bindir)
shutil.copy(ceftests, bindir)
# END: Copy cefclient, cefsimple, ceftests
# Copy libraries
if platform.system() == "Windows":
# libcef.lib and cef_sandbox.lib
mvfiles(bindir, libdir, ".lib")
# MT lib
libsrc = os.path.join(src, "build_wrapper_mt", "libcef_dll_wrapper",
"libcef_dll_wrapper.lib")
libdst = os.path.join(libdir, "libcef_dll_wrapper_mt.lib")
shutil.copy(libsrc, libdst)
# MD lib
libsrc = os.path.join(src, "build_wrapper_md", "libcef_dll_wrapper",
"libcef_dll_wrapper.lib")
libdst = os.path.join(libdir, "libcef_dll_wrapper_md.lib")
shutil.copy(libsrc, libdst)
elif platform.system() == "Linux":
cpdir(os.path.join(src, "build_cefclient", "libcef_dll_wrapper"),
libdir)
# Remove .lib files from bin/ only after libraries were copied
libs = glob.glob(os.path.join(bindir, "*.lib"))
for lib in libs:
os.remove(lib)
# Remove cef_sandbox.lib (huge file)
cef_sandbox = os.path.join(libdir, "cef_sandbox.lib")
if os.path.exists(cef_sandbox):
os.remove(cef_sandbox)
# Copy README.txt and LICENSE.txt
shutil.copy(os.path.join(src, "README.txt"), dst)
shutil.copy(os.path.join(src, "LICENSE.txt"), dst)
print("[automate.py] OK prebuilt binaries created in '%s/'" % dst)
def get_msvs_for_python():
"""Get MSVS version (eg 2008) for current python running."""
if sys.version_info[:2] == (2, 7):
return "2008"
elif sys.version_info[:2] == (3, 4):
return "2010"
elif sys.version_info[:2] == (3, 5):
return "2015"
else:
print("ERROR: This python version is not yet supported")
sys.exit(1)
def getenv():
"""Env variables passed to shell when running commands."""
env = os.environ
env["PATH"] = Options.depot_tools_dir + os.pathsep + env["PATH"]
env["GYP_GENERATORS"] = Options.gyp_generators
if platform.system() == "Windows":
env["GYP_MSVS_VERSION"] = Options.gyp_msvs_version
# See cef/AutomatedBuildSetup.md for reference.
# Issue73 patch applied with "use_allocator=none"
# TODO: 32-bit gyp defines: host_arch=x86_64 target_arch=ia32
env["GN_DEFINES"] = "use_sysroot=true use_allocator=none symbol_level=1"
# To perform an official build set GYP_DEFINES=buildtype=Official.
# This will disable debugging code and enable additional link-time
# optimizations in Release builds.
if Options.release_build and not Options.fast_build:
env["GN_DEFINES"] += " is_official_build=true"
# Modifications to automate-git.py
env["CEFPYTHON_NINJA_JOBS"] = str(Options.ninja_jobs)
return env
def run_command(command, working_dir):
"""Run command in a given directory with env variables set.
On Linux multiple commands on one line with the use of && are not allowed.
"""
print("[automate.py] Running '"+" ".join(command)+"' in '" +
working_dir+"'...")
if isinstance(command, str):
args = shlex.split(command.replace("\\", "\\\\"))
else:
args = command
return subprocess.check_call(args, cwd=working_dir, env=getenv(),
shell=(platform.system() == "Windows"))
def run_python(command_line, working_dir):
"""Run python script using depot_tools."""
python = "python"
return run_command("%s %s" % (python, command_line), working_dir)
def run_git(command_line, working_dir):
"""Run git command using depot_tools."""
return run_command("git %s" % command_line, working_dir)
def run_automate_git():
"""Run CEF automate-git.py."""
script = os.path.join(Options.cefpython_dir, "tools", "automate-git.py")
"""
Example automate-git.py command:
C:\chromium>call python automate-git.py --download-dir=./test/
--branch=2526 --no-debug-build --verbose-build
Run ninja build manually:
cd chromium/src
ninja -v -j2 -Cout\Release cefclient
"""
args = []
if ARCH64:
args.append("--x64-build")
args.append("--download-dir=" + Options.cef_build_dir)
args.append("--branch=" + Options.cef_branch)
if Options.release_build:
args.append("--no-debug-build")
args.append("--verbose-build")
# --force-build sets --force-distrib by default
# ninja will only recompile files that changed
args.append("--force-build")
# We clone cef repository ourselves and update cef patches with ours,
# so don't fetch/update CEF repo.
args.append("--no-cef-update")
# Force Chromium update so that gclient sync is called. It may fail
# sometimes with files missing and must re-run to fix.
if Options.force_chromium_update:
args.append("--force-update")
args.append("--no-distrib-archive")
if platform.system() == "Linux":
# Building cefclient target isn't supported on Linux when
# using sysroot (cef/#1916). However building cefclient
# later in cef_binary/ with cmake/ninja do works fine.
args.append("--build-target=cefsimple")
args = " ".join(args)
return run_python(script+" "+args, Options.cef_build_dir)
def rmdir(path):
"""Delete directory recursively."""
if os.path.exists(path):
print("[automate.py] Removing directory %s" % path)
shutil.rmtree(path, onerror=onerror)
def cpdir(src, dst):
"""An equivalent of linux 'cp -r src/* dst/'. """
names = os.listdir(src)
if not os.path.exists(dst):
os.makedirs(dst)
for name in names:
path = os.path.join(src, name)
if os.path.isdir(path):
dst_subdir = os.path.join(dst, name)
shutil.copytree(path, dst_subdir)
else:
shutil.copy(path, dst)
def mvfiles(src, dst, ext):
"""An equivalent of linux 'mv src/*.ext dst/'. """
names = os.listdir(src)
if not os.path.exists(dst):
os.makedirs(dst)
for name in names:
path = os.path.join(src, name)
if os.path.isfile(path) and name.endswith(ext):
shutil.copy(path, dst)
def onerror(func, path, _):
"""Fix file permission on error and retry operation."""
if not os.access(path, os.W_OK):
os.chmod(path, stat.S_IWUSR)
func(path)
else:
raise Exception("Not a file permission error, dunno what to do")
def get_prebuilt_name(header_file=""):
if header_file:
version = get_version_from_file(header_file)
else:
version = get_cefpython_version()
name = "cef%s_%s_%s" % (
version["CHROME_VERSION_MAJOR"],
version["CEF_VERSION"],
OS_POSTFIX2,
)
return name
if __name__ == "__main__":
main()