chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.38k stars 467 forks source link

Add Bazel config for building CEF binary distribution #3757

Open magreenblatt opened 3 months ago

magreenblatt commented 3 months ago

Is your feature request related to a problem? Please describe. Bazel is a popular alternative to CMake for building applications. We should provide sample configurations for Bazel as part of the CEF binary distribution.

Describe the solution you'd like Build the CEF sample apps in a binary distribution using Bazel and the default platform toolchain.

Additional context Bazel default platform toolchains are tested to work for Windows x64, MacOS ARM64 and x64 (cross-compile from ARM64), and Linux x64. They are known to be broken for Windows x86 (cross-compile from x64). Other platforms/architectures are untested and may require custom toolchain definitions (Linux examples here).

magreenblatt commented 3 months ago

Initial Bazel support is considered complete (working) in version 127.1.5+g35f74cc+chromium-127.0.6533.89.

Building with Bazel works as follows:

  1. Install Bazelisk.
  2. Download/extract a CEF binary distribution that includes Bazel support.
  3. Build and run using Bazel:
    
    $ cd /path/to/cef_binary_*
    $ bazel build //tests/cefclient 

On Mac/Linux:

$ bazel run //tests/cefclient

On Windows:

$ bazel run //tests/cefclient/win:cefclient.exe



Platform-specific instructions are included in the binary distribution `README.txt` file.

See [cef-project](https://github.com/chromiumembedded/cef-project) for an example Bazel project that utilizes the CEF binary distribution as an external dependency.

Notes:

- Add `-c dbg` for a Debug build
- Add `--cpu=darwin_x86_64` for a Mac x64 cross-compile build on ARM64 host
- Arguments can be passed to the app when using `run` by adding `-- [...]` at the end
magreenblatt commented 3 months ago

In-progress PR: https://bitbucket.org/chromiumembedded/cef/pull-requests/786

magreenblatt commented 3 months ago

Remaining work:

Related to C++ compiler/toolchain configuration:

magreenblatt commented 3 months ago

Figure out how to consume the CEF binary distribution (as repository or module) from a third-party Bazel project.

(For background see https://bazel.build/external/overview)

The http_archive rule allows us to download an archive file, and optionally override the associated BUILD and/or WORKSPACE file. We'll need a convenient way to collect download URLs and sha256 values for all platform builds of a particular release. For example, see https://github.com/chromiumembedded/cef/issues/3757#issuecomment-2261296637.

magreenblatt commented 3 months ago

We'll need a convenient way to collect download URLs and sha256 values

The Spotify builder now provides <file>.sha256 for all binaries beginning with version 127.1.2.

magreenblatt commented 3 months ago

The http_archive rule allows us to download an archive file, and optionally override the associated BUILD and/or WORKSPACE file.

Unfortunately this approach has a number of limitations. For example:

We will therefore provide a separate script for downloading the CEF binary distribution and writing a version.bzl file, to be run manually before bazel build. The WORKSPACE configuration then becomes:

load(":third_party/cef/version.bzl", "CEF_VERSION", "CEF_PLATFORM")

local_repository(
    name = "cef",
    path = "third_party/cef/cef_binary_{}_{}".format(CEF_VERSION, CEF_PLATFORM),
)
magreenblatt commented 3 months ago

We can download a platform/arch-specific archive as name="cef_<platform>" and create target-specific aliases from @cef to @cef_<platform> using select({})

Here's an example of this approach for future reference:

## `WORKSPACE` contents:

local_repository(
    name = "cef",
    path = "bazel/cef",
)
load("@cef//:repos.bzl", "install_cef_repos")
install_cef_repos()

## `bazel/cef/BUILD.bazel` contents:

# Alias all targets to the platform/arch-specific repo.
alias(
    name = "cef_wrapper",
    actual = select({
        "@//:macos_arm64": "@cef_macosarm64//:cef_wrapper",
        # ...
    }),
)

# ...

## `bazel/cef/repos.bzl` contents:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

CEF_DOWNLOAD_URL = "https://cef-builds.spotifycdn.com/"
CEF_VERSION = "127.1.2+g1cd2424+chromium-127.0.6533.73"

def add_cef_repo(
        platform,
        sha256,
        version = CEF_VERSION,
        url = CEF_DOWNLOAD_URL):
    file_name = "cef_binary_{}_{}".format(version, platform)
    http_archive(
        name = "cef_{0}".format(platform),
        sha256 = sha256,
        strip_prefix = file_name,
        url = "{}{}".format(url, file_name),
    )

def install_cef_repos():
    """
      Set up definitions of all repos for each supported platform/arch.
    """
    add_cef_repo(platform = "macosarm64", sha256 = "d2e9ead...")
    # ...
magreenblatt commented 3 months ago

We will therefore provide a separate script for downloading the CEF binary distribution

There's also a middle ground where the script writes the platform but Bazel still performs the download:

## `cef_config.bzl` contents (written by script):

CEF_PLATFORM = "macosarm64"

## `WORKSPACE` contents:

load("//:cef_config.bzl", "CEF_PLATFORM")
load("//:bazel/cef_loader.bzl", "load_cef_repo")
load_cef_repo(CEF_PLATFORM)

## `bazel/cef_loader.bzl` contents:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

CEF_DOWNLOAD_URL = "https://cef-builds.spotifycdn.com/"
CEF_VERSION = "127.1.2+g1cd2424+chromium-127.0.6533.73"
CEF_FILE_SHA256 = {
    # Map of each platform name to sha256 hash.
    "macosarm64": "d2e9ead6...",
    # ...
}

def load_cef_repo(platform
                  name = "cef",
                  version = CEF_VERSION,
                  url = CEF_DOWNLOAD_URL):
    """
    Download, extract and load a CEF binary distribution.
    """
    file_name = "cef_binary_{}_{}".format(version, platform)

    http_archive(
        name = name,
        sha256 = CEF_FILE_SHA256[platform],
        strip_prefix = file_name,
        url = "{}{}.tar.bz2".format(url, file_name),
    )
magreenblatt commented 3 months ago

Bazel build support has been added to cef-project, see instructions.

magreenblatt commented 3 months ago

The Bazel fastbuild configuration is a bit of an oddity. From the docs:

fastbuild means build as fast as possible: generate minimal debugging information (-gmlt
-Wl,-S), and don’t optimize. This is the default. Note: -DNDEBUG will not be set.

CEF provides Debug and Release configs. CEF currently treats fastbuild the same as opt (Release) because, on Windows, fastbuild sets /MT (non-Debug runtime library) due to --features=static_link_msvcrt (code here). However, the Release config also defines NDEBUG which conflicts with the above fastbuild docs.

We therefore recommend that users avoid fastbuild when integrating CEF into existing Bazel configs. Instead, explicitly select the dbg (Debug) or opt (Release) config.

magreenblatt commented 1 month ago

We may revisit the cc_import shared_library config that currently copies libcef.dll as a transitive dependency. This seems to cause issues with complex dependency graphs, and it may be better to instead explicitly link libcef.lib and explicitly copy libcef.dll.