def _build_project()

in builder/actions/cmake.py [0:0]


def _build_project(env, project, cmake_extra, build_tests=False, args_transformer=None):
    sh = env.shell
    config = project.get_config(env.spec)
    toolchain = env.toolchain
    # build dependencies first, let cmake decide what needs doing
    for dep in project.get_dependencies(env.spec):
        _build_project(env, dep, cmake_extra)

    project_source_dir, project_build_dir, project_install_dir = _project_dirs(
        env, project)
    abs_project_build_dir = project_build_dir
    if not os.path.isabs(project_build_dir):
        abs_project_build_dir = os.path.join(env.root_dir, project_build_dir)
    sh.mkdir(abs_project_build_dir)

    # If cmake has already run, assume we're good
    if os.path.isfile(os.path.join(abs_project_build_dir, 'CMakeCache.txt')):
        return

    cmake = toolchain.cmake_binary()
    cmake_version = toolchain.cmake_version()
    assert cmake_version != None

    # TODO These platforms don't succeed when doing a RelWithDebInfo build
    build_config = env.args.config
    if toolchain.host in ("al2012", "manylinux"):
        build_config = "Debug"

    # Set compiler flags
    compiler_flags = []
    if toolchain.compiler != 'default' and toolchain.compiler != 'msvc' and not toolchain.cross_compile:
        c_path = toolchain.compiler_path()
        cxx_path = toolchain.cxx_compiler_path()
        for opt, value in [('c', c_path), ('cxx', cxx_path)]:
            if value:
                compiler_flags.append(
                    '-DCMAKE_{}_COMPILER={}'.format(opt.upper(), value))

    cmake_args = UniqueList([
        "-B{}".format(project_build_dir),
        "-H{}".format(project_source_dir),
        # "-Werror=dev",
        # "-Werror=deprecated",
        "-DAWS_WARNINGS_ARE_ERRORS=ON",
        "-DCMAKE_INSTALL_PREFIX=" + project_install_dir,
        "-DCMAKE_PREFIX_PATH=" + project_install_dir,
        "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
        "-DCMAKE_BUILD_TYPE=" + build_config,
        "-DBUILD_TESTING=" + ("ON" if build_tests else "OFF"),
        *compiler_flags,
    ])
    # Merging in cmake_args from all upstream projects inevitably leads to duplicate arguments.
    # Using a UniqueList seems to solve the problem well enough for now.
    cmake_args += project.cmake_args(env)
    cmake_args += cmake_extra

    # Allow caller to programmatically tweak the cmake_args,
    # as a last resort in case data merging wasn't working out
    if args_transformer:
        cmake_args = args_transformer(env, project, cmake_args)

    # When cross compiling, we must inject the build_env into the cross compile container
    build_env = []
    if toolchain.cross_compile:
        build_env = ['{}={}\n'.format(key, val)
                     for key, val in config.get('build_env', {}).items()]
        with open(toolchain.env_file, 'a') as f:
            f.writelines(build_env)

    # set parallism via env var (cmake's --parallel CLI option doesn't exist until 3.12)
    if os.environ.get('CMAKE_BUILD_PARALLEL_LEVEL') is None:
        sh.setenv('CMAKE_BUILD_PARALLEL_LEVEL', str(os.cpu_count()))

    working_dir = env.root_dir if toolchain.cross_compile else os.getcwd()

    # configure
    sh.exec(*toolchain.shell_env, cmake, cmake_args, working_dir=working_dir, check=True)

    # build & install
    sh.exec(*toolchain.shell_env, cmake, "--build", project_build_dir, "--config",
            build_config, "--target", "install", working_dir=working_dir, check=True)