From d4880f8facc987cac404642dc6f63f72bf6d3530 Mon Sep 17 00:00:00 2001 From: irengrig Date: Wed, 22 Aug 2018 22:06:37 +0200 Subject: [PATCH] build cmake if it is missing (should be configurable) (#57) --- WORKSPACE | 9 ++++++ examples/build_cmake_itself/BUILD | 6 ++++ tools/build_defs/BUILD | 2 ++ tools/build_defs/cmake.bzl | 14 ++++++++- tools/build_defs/cmake_build.bzl | 38 ++++++++++++++++++++++ tools/build_defs/detect_root.bzl | 48 ++++++++++++++++++++++++++++ tools/build_defs/framework.bzl | 48 +--------------------------- tools/build_defs/ninja_build.bzl | 5 ++- workspace_definitions.bzl | 52 +++++++++++++++++++++++++++++-- 9 files changed, 169 insertions(+), 53 deletions(-) create mode 100644 examples/build_cmake_itself/BUILD create mode 100644 tools/build_defs/cmake_build.bzl create mode 100644 tools/build_defs/detect_root.bzl diff --git a/WORKSPACE b/WORKSPACE index 15be9f29..3b89986e 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -131,3 +131,12 @@ http_archive( "https://github.com/nghttp2/nghttp2/archive/e5b3f9addd49bca27e2f99c5c65a564eb5c0cf6d.tar.gz", ], ) + +http_archive( + name = "cmake", + build_file_content = all_content, + strip_prefix = "CMake-3.12.1", + urls = [ + "https://github.com/Kitware/CMake/archive/v3.12.1.tar.gz", + ], +) diff --git a/examples/build_cmake_itself/BUILD b/examples/build_cmake_itself/BUILD new file mode 100644 index 00000000..785d1b4f --- /dev/null +++ b/examples/build_cmake_itself/BUILD @@ -0,0 +1,6 @@ +load("//tools/build_defs:cmake_build.bzl", "cmake_tool") + +cmake_tool( + name = "cmaketool", + cmake_srcs = "@cmake//:all", +) diff --git a/tools/build_defs/BUILD b/tools/build_defs/BUILD index 3f740c93..7fd843ab 100644 --- a/tools/build_defs/BUILD +++ b/tools/build_defs/BUILD @@ -3,5 +3,7 @@ exports_files( "utils.sh", "cmake.bzl", "framework.bzl", + "ninja_build.bzl", + "cmake_build.bzl", ], ) diff --git a/tools/build_defs/cmake.bzl b/tools/build_defs/cmake.bzl index 380bd953..ecec641f 100644 --- a/tools/build_defs/cmake.bzl +++ b/tools/build_defs/cmake.bzl @@ -6,9 +6,13 @@ load( "CC_EXTERNAL_RULE_ATTRIBUTES", "cc_external_rule_impl", "create_attrs", +) +load( + "//tools/build_defs:detect_root.bzl", "detect_root", ) load("//tools/build_defs:cc_toolchain_util.bzl", "absolutize_path_in_str", "getFlagsInfo", "getToolsInfo") +load("@foreign_cc_platform_utils//:cmake_globals.bzl", "CMAKE_COMMAND", "CMAKE_DEPS") def _cmake_external(ctx): options = " ".join(ctx.attr.cmake_options) @@ -22,7 +26,7 @@ def _cmake_external(ctx): cmake_string = " ".join([ " ".join(_get_toolchain_variables(ctx, tools, flags)), - " cmake", + " " + CMAKE_COMMAND, " ".join(cache_entries), "-DCMAKE_PREFIX_PATH=\"$EXT_BUILD_DEPS\"", "-DCMAKE_INSTALL_PREFIX=\"{}\"".format(install_prefix), @@ -31,11 +35,13 @@ def _cmake_external(ctx): ]) copy_results = "copy_dir_contents_to_dir $TMPDIR/{} $INSTALLDIR".format(install_prefix) + tools_deps = ctx.attr.tools_deps + [ctx.attr._cmake_dep] attrs = create_attrs( ctx.attr, configure_name = "CMake", configure_script = cmake_string, postfix_script = copy_results + "\n" + ctx.attr.postfix_script, + tools_deps = tools_deps, ) return cc_external_rule_impl(ctx, attrs) @@ -143,6 +149,12 @@ def _attrs(): "env_vars": attr.string_dict(mandatory = False, default = {}), # Other CMake options "cmake_options": attr.string_list(mandatory = False, default = []), + "_cmake_dep": attr.label( + default = "@foreign_cc_platform_utils//:cmake", + cfg = "target", + allow_files = True, + # allow_single_file = True, + ), }) return attrs diff --git a/tools/build_defs/cmake_build.bzl b/tools/build_defs/cmake_build.bzl new file mode 100644 index 00000000..5e415a59 --- /dev/null +++ b/tools/build_defs/cmake_build.bzl @@ -0,0 +1,38 @@ +load(":detect_root.bzl", "detect_root") + +def _cmake_tool(ctx): + root = detect_root(ctx.attr.cmake_srcs) + + cmake = ctx.actions.declare_directory("cmake") + script_text = "\n".join([ + "BUILD_DIR=$(pwd)", + "export TMPDIR=$(mktemp -d)", + "cp -R ./{}/. $TMPDIR".format(root), + "mkdir " + cmake.path, + "pushd $TMPDIR", + "./bootstrap --prefix=install", + "make install", + "cp -a ./install/. $BUILD_DIR/" + cmake.path, + "popd", + ]) + + ctx.actions.run_shell( + mnemonic = "BootstrapCMake", + inputs = ctx.attr.cmake_srcs.files, + outputs = [cmake], + tools = [], + use_default_shell_env = True, + command = script_text, + execution_requirements = {"block-network": ""}, + ) + + return [DefaultInfo(files = depset([cmake]))] + +cmake_tool = rule( + attrs = { + "cmake_srcs": attr.label(mandatory = True), + }, + fragments = ["cpp"], + output_to_genfiles = True, + implementation = _cmake_tool, +) diff --git a/tools/build_defs/detect_root.bzl b/tools/build_defs/detect_root.bzl new file mode 100644 index 00000000..74e8d1b9 --- /dev/null +++ b/tools/build_defs/detect_root.bzl @@ -0,0 +1,48 @@ +def detect_root(source): + """Detects the path to the topmost directory of the 'source' outputs. + To be used with external build systems to point to the source code/tools directories. + + If the target groups the sources of the external dependency, the workspace root is used, + and no other checks are performed (i.e. it is assumed that the whole contents of the external + dependency is used). + Otherwise, for the "usual" targets, target's files are iterated and the path with the least length + is selected. + """ + + # root = source.label.workspace_root + root = "" + sources = source.files + if (root and len(root) > 0) or len(sources) == 0: + return root + + root = "" + level = -1 + num_at_level = 0 + + # find topmost directory + for file in sources: + file_level = _get_level(file.path) + if level == -1 or level > file_level: + root = file.path + level = file_level + num_at_level = 1 + elif level == file_level: + num_at_level += 1 + + if num_at_level == 1: + return root + + (before, sep, after) = root.rpartition("/") + if before and sep and after: + return before + return root + +def _get_level(path): + normalized = path + for i in range(len(path)): + new_normalized = normalized.replace("//", "/") + if len(new_normalized) == len(normalized): + break + normalized = new_normalized + + return normalized.count("/") diff --git a/tools/build_defs/framework.bzl b/tools/build_defs/framework.bzl index 6881afeb..28a757d9 100644 --- a/tools/build_defs/framework.bzl +++ b/tools/build_defs/framework.bzl @@ -9,6 +9,7 @@ load( "create_linking_info", "targets_windows", ) +load("//tools/build_defs:detect_root.bzl", "detect_root") """ Dict with definitions of the context attributes, that customize cc_external_rule_impl function. Many of the attributes have default values. @@ -464,50 +465,3 @@ def _collect_flags(cc_linking): for params in _extract_link_params(cc_linking): linkopts = params.linkopts.to_list() return collections.uniq(linkopts) - -def detect_root(source): - """Detects the path to the topmost directory of the 'source' outputs. - To be used with external build systems to point to the source code/tools directories. - - If the target groups the sources of the external dependency, the workspace root is used, - and no other checks are performed (i.e. it is assumed that the whole contents of the external - dependency is used). - Otherwise, for the "usual" targets, target's files are iterated and the path with the least length - is selected. - """ - root = source.label.workspace_root - sources = source.files - if (root and len(root) > 0) or len(sources) == 0: - return root - - root = "" - level = -1 - num_at_level = 0 - - # find topmost directory - for file in sources: - file_level = _get_level(file.path) - if level == -1 or level > file_level: - root = file.path - level = file_level - num_at_level = 1 - elif level == file_level: - num_at_level += 1 - - if num_at_level == 1: - return root - - (before, sep, after) = root.rpartition("/") - if before and sep and after: - return before - return root - -def _get_level(path): - normalized = path - for i in range(len(path)): - new_normalized = normalized.replace("//", "/") - if len(new_normalized) == len(normalized): - break - normalized = new_normalized - - return normalized.count("/") diff --git a/tools/build_defs/ninja_build.bzl b/tools/build_defs/ninja_build.bzl index 548648c4..22180a77 100644 --- a/tools/build_defs/ninja_build.bzl +++ b/tools/build_defs/ninja_build.bzl @@ -1,4 +1,4 @@ -load("//tools/build_defs:framework.bzl", "detect_root") +load("//tools/build_defs:detect_root.bzl", "detect_root") def _ninja_tool(ctx): root = detect_root(ctx.attr.ninja_srcs) @@ -6,9 +6,8 @@ def _ninja_tool(ctx): ninja = ctx.actions.declare_directory("ninja") script_text = "\n".join([ "mkdir " + ninja.path, - "cp -r ./{}/** {}".format(root, ninja.path), + "cp -R ./{}/. {}".format(root, ninja.path), "cd " + ninja.path, - "pwd", "./configure.py --bootstrap", ]) diff --git a/workspace_definitions.bzl b/workspace_definitions.bzl index 65e8e3e5..e4b05635 100644 --- a/workspace_definitions.bzl +++ b/workspace_definitions.bzl @@ -8,14 +8,62 @@ def _define_shell_utils_impl(rctx): if os_name.find("windows") != -1: utils_name = "utils_win.bat" fail("Not supported yet!") - rctx.file("WORKSPACE", "workspace(name='foreign_cc_platform_utils')") + + existing_cmake = rctx.which("cmake") + + is_ci = rctx.os.environ.get("CI") + print("IS_CI: " + str(is_ci)) + + cmake_globals_text = "" + cmake_text = "" + if existing_cmake != None: + cmake_globals_text = """ +CMAKE_COMMAND="cmake" +CMAKE_DEPS=[] +""" + cmake_text = """ +sh_library( + name = "cmake", + visibility = ["//visibility:public"] +) +""" + else: + path_to_cmake_build = rctx.path(Label("//tools/build_defs:cmake_build.bzl")) + rctx.template("cmake_build.bzl", path_to_cmake_build) + + path_to_detect_root = rctx.path(Label("//tools/build_defs:detect_root.bzl")) + rctx.template("detect_root.bzl", path_to_detect_root) + + cmake_globals_text = """ +CMAKE_COMMAND="$EXT_BUILD_DEPS/bin/cmake/bin/cmake" +CMAKE_DEPS=[Label("@foreign_cc_platform_utils//:cmake")] +""" + cmake_text = """ +sh_library( + name = "cmake", + srcs = [":cmake_externally_built"], + visibility = ["//visibility:public"] +) + +load("//:cmake_build.bzl", "cmake_tool") +cmake_tool( + name = "cmake_externally_built", + cmake_srcs = "@cmake//:all" +) +""" + + rctx.file("cmake_globals.bzl", cmake_globals_text) + + rctx.file("WORKSPACE", """workspace(name='foreign_cc_platform_utils')""") + rctx.file("BUILD.bazel", """ sh_library( name = "shell_utils", srcs = ["{}"], visibility = ["//visibility:public"] ) -""".format(utils_name)) +""".format(utils_name) + cmake_text) + path = rctx.path(Label("//tools/build_defs:" + utils_name)) rctx.template(utils_name, path, executable = True)