diff --git a/.github/docs-0.1.0.patch b/.github/docs-0.1.0.patch index ec291f3c..5015ed70 100644 --- a/.github/docs-0.1.0.patch +++ b/.github/docs-0.1.0.patch @@ -4,7 +4,7 @@ index a5a37ac..e381ce8 100644 +++ b/docs/BUILD.bazel @@ -35,7 +35,7 @@ genrule( cmd = """cat << EOF > $@ - #!/bin/bash + #!/usr/bin/env bash set -e -cat \\$${BUILD_WORKSPACE_DIRECTORY}/$(location //:docs) > \\$${BUILD_WORKSPACE_DIRECTORY}/README.md +cat \\$${BUILD_WORKSPACE_DIRECTORY}/$(location //:docs) > \\$${BUILD_WORKSPACE_DIRECTORY}/src/index.md diff --git a/.github/docs-0.2.0.patch b/.github/docs-0.2.0.patch index 0b84bb3a..c0f3b26f 100644 --- a/.github/docs-0.2.0.patch +++ b/.github/docs-0.2.0.patch @@ -4,7 +4,7 @@ index a5a37ac..091e679 100644 +++ b/docs/BUILD.bazel @@ -35,7 +35,7 @@ genrule( cmd = """cat << EOF > $@ - #!/bin/bash + #!/usr/bin/env bash set -e -cat \\$${BUILD_WORKSPACE_DIRECTORY}/$(location //:docs) > \\$${BUILD_WORKSPACE_DIRECTORY}/README.md +cat \\$${BUILD_WORKSPACE_DIRECTORY}/$(location //:docs) > \\$${BUILD_WORKSPACE_DIRECTORY}/src/index.md diff --git a/.github/docs-0.3.0.patch b/.github/docs-0.3.0.patch index 5f90b410..f7460ddd 100644 --- a/.github/docs-0.3.0.patch +++ b/.github/docs-0.3.0.patch @@ -10,7 +10,7 @@ index 461df15..efa4c26 100644 + srcs = DOCS_TARGETS + ["index.md"], outs = ["generate_docs.sh"], cmd = """cat << EOF > $@ - #!/bin/bash + #!/usr/bin/env bash set -euo pipefail -cat \\$${BUILD_WORKSPACE_DIRECTORY}/$(location //:flatten_docs) > \\$${BUILD_WORKSPACE_DIRECTORY}/flatten.md -cat \\$${BUILD_WORKSPACE_DIRECTORY}/$(location //:cmake_docs) > \\$${BUILD_WORKSPACE_DIRECTORY}/cmake.md diff --git a/README.md b/README.md index ad0a2bdb..65d626c6 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,10 @@ For more generalized updates, please see [NEWS.md](./NEWS.md) or checkout the [ccb]: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_binary [ccl]: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_library [cct]: https://docs.bazel.build/versions/master/be/c-cpp.html#cc_toolchain + +## Caveats + +* FreeBSD support is currently experimental and on a best-effort basis. + Google currently doesn't have a CI test environment for FreeBSD, + but please make your voice heard by upvoting this + [issue](https://github.com/bazelbuild/continuous-integration/issues/258). diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 4d5dd659..1ea7f902 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -92,7 +92,7 @@ export COMMIT="$$(cat bazel-out/stable-status.txt | grep STABLE_SCM_VERSION | cu export SHORT_COMMIT="$$(cat bazel-out/stable-status.txt | grep STABLE_SCM_SHORT_VERSION | cut -d' ' -f2)" export RELEASE="$$(cat bazel-out/stable-status.txt | grep STABLE_RELEASE | cut -d' ' -f2)" cat << EOF > $@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail short_commit="$${SHORT_COMMIT}" diff --git a/docs/gen_header.sh b/docs/gen_header.sh index d0137fd0..16cfcbe3 100755 --- a/docs/gen_header.sh +++ b/docs/gen_header.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail diff --git a/docs/tools/workspace_status.sh b/docs/tools/workspace_status.sh index eaec25a8..5ceb3f76 100755 --- a/docs/tools/workspace_status.sh +++ b/docs/tools/workspace_status.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash set -euo pipefail diff --git a/examples/configure_with_bazel_transitive/simple_lib/configure b/examples/configure_with_bazel_transitive/simple_lib/configure index 3a5cb183..52db02df 100755 --- a/examples/configure_with_bazel_transitive/simple_lib/configure +++ b/examples/configure_with_bazel_transitive/simple_lib/configure @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash echo "# simple" > Makefile echo "CC = ${CC}" > Makefile diff --git a/examples/make_simple/code/cxx_wrapper.sh b/examples/make_simple/code/cxx_wrapper.sh index dc63ca51..cad76989 100755 --- a/examples/make_simple/code/cxx_wrapper.sh +++ b/examples/make_simple/code/cxx_wrapper.sh @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -o errexit +set -o nounset if [[ $(uname) == *"NT"* ]]; then # If Windows diff --git a/examples/ninja_simple/code/clang_wrapper.sh b/examples/ninja_simple/code/clang_wrapper.sh index d98fdff6..9dfc4b21 100755 --- a/examples/ninja_simple/code/clang_wrapper.sh +++ b/examples/ninja_simple/code/clang_wrapper.sh @@ -1,4 +1,7 @@ -#!/bin/bash -eu +#!/usr/bin/env bash + +set -o errexit +set -o nounset if [[ $(uname) == *"NT"* ]]; then # If Windows diff --git a/examples/third_party/gn/gn_test.sh b/examples/third_party/gn/gn_test.sh index 509e85ce..95f9560e 100755 --- a/examples/third_party/gn/gn_test.sh +++ b/examples/third_party/gn/gn_test.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [[ ! -e "$GN" ]]; then echo "gn does not exist" diff --git a/examples/third_party/gn/patch.gen_ninja.sh b/examples/third_party/gn/patch.gen_ninja.sh index b175c5a9..0e4b5648 100755 --- a/examples/third_party/gn/patch.gen_ninja.sh +++ b/examples/third_party/gn/patch.gen_ninja.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [[ "$OSTYPE" == "win32" ]]; then python.exe build/gen.py --no-last-commit-position diff --git a/foreign_cc/private/framework/toolchains/freebsd_commands.bzl b/foreign_cc/private/framework/toolchains/freebsd_commands.bzl new file mode 100644 index 00000000..4d5240f8 --- /dev/null +++ b/foreign_cc/private/framework/toolchains/freebsd_commands.bzl @@ -0,0 +1,263 @@ +"""Define default foreign_cc framework commands. + +FreeBSD doesn't use bash by default but users can install it +using: + + $ sudo pkg install bash + +Also, Bash is one of the prerequisites for Bazel: +https://docs.bazel.build/versions/main/install-compile-source.html#bootstrap-unix-prereq +""" + +load(":commands.bzl", "FunctionAndCallInfo") + +def shebang(): + return "#!/usr/bin/env bash" + +def script_extension(): + return ".sh" + +def pwd(): + return "$(pwd)" + +def echo(text): + return "echo \"{text}\"".format(text = text) + +def export_var(name, value): + return "export {name}={value}".format(name = name, value = value) + +def local_var(name, value): + return "local {name}={value}".format(name = name, value = value) + +def use_var(name): + return "$" + name + +def env(): + return "env" + +def path(expression): + return "export PATH=\"{expression}:$PATH\"".format(expression = expression) + +def touch(path): + return "touch " + path + +def enable_tracing(): + return "set -x" + +def disable_tracing(): + return "set +x" + +def mkdirs(path): + return "mkdir -p " + path + +def rm_rf(path): + return "rm -rf " + path + +def if_else(condition, if_text, else_text): + return """\ +if [ {condition} ]; then + {if_text} +else + {else_text} +fi +""".format(condition = condition, if_text = if_text, else_text = else_text) + +# buildifier: disable=function-docstring +def define_function(name, text): + lines = [] + lines.append("function " + name + "() {") + for line_ in text.splitlines(): + lines.append(" " + line_) + lines.append("}") + return "\n".join(lines) + +def replace_in_files(dir, from_, to_): + return FunctionAndCallInfo( + text = """\ +if [ -d "$1" ]; then + SAVEIFS=$IFS + IFS=$'\n' + # Find all real files. Symlinks are assumed to be relative to something within the directory we're seaching and thus ignored + local files=$(find -P -f $1 \\( -type f -and \\( -name "*.pc" -or -name "*.la" -or -name "*-config" -or -name "*.mk" -or -name "*.cmake" \\) \\)) + IFS=$SAVEIFS + for file in ${files[@]}; do + local backup=$(mktemp) + touch -r "${file}" "${backup}" + sed -i '' -e 's@'"$2"'@'"$3"'@g' "${file}" + if [[ "$?" -ne "0" ]]; then + exit 1 + fi + touch -r "${backup}" "${file}" + rm "${backup}" + done +fi +""", + ) + +def copy_dir_contents_to_dir(source, target): + # Beause FreeBSD `cp` doesn't have `--no-copy-directory`, we have to + # do something more complex for this environment. + return """\ +if [[ -d "{source}" ]]; then + cp -L -R "{source}"/* "{target}" +else + cp -L -R "{source}" "{target}" +fi +find {target} -type f -exec touch -r "{source}" "{{}}" \\; +""".format( + source = source, + target = target, + ) + +def symlink_contents_to_dir(source, target): + text = """\ +if [[ -z "$1" ]]; then + echo "arg 1 to symlink_contents_to_dir is unexpectedly empty" + exit 1 +fi +if [[ -z "$2" ]]; then + echo "arg 2 to symlink_contents_to_dir is unexpectedly empty" + exit 1 +fi +local target="$2" +mkdir -p "$target" +if [[ -f "$1" ]]; then + ##symlink_to_dir## "$1" "$target" +elif [[ -L "$1" && ! -d "$1" ]]; then + local actual=$(readlink "$1") + ##symlink_contents_to_dir## "$actual" "$target" +elif [[ -d "$1" ]]; then + SAVEIFS=$IFS + IFS=$'\n' + local children=($(find "$1/" -maxdepth 1 -mindepth 1)) + IFS=$SAVEIFS + for child in "${children[@]:-}"; do + ##symlink_to_dir## "$child" "$target" + done +fi +""" + return FunctionAndCallInfo(text = text) + +def symlink_to_dir(source, target): + text = """\ +if [[ -z "$1" ]]; then + echo "arg 1 to symlink_to_dir is unexpectedly empty" + exit 1 +fi +if [[ -z "$2" ]]; then + echo "arg 2 to symlink_to_dir is unexpectedly empty" + exit 1 +fi +local target="$2" +mkdir -p "$target" +if [[ -f "$1" ]]; then + # In order to be able to use `replace_in_files`, we ensure that we create copies of specfieid + # files so updating them is possible. + if [[ "$1" == *.pc || "$1" == *.la || "$1" == *-config || "$1" == *.mk || "$1" == *.cmake ]]; then + dest="$target/$(basename $1)" + cp "$1" "$dest" && chmod +w "$dest" && touch -r "$1" "$dest" + else + ln -s -f "$1" "$target" + fi +elif [[ -L "$1" && ! -d "$1" ]]; then + cp -pR "$1" "$2" +elif [[ -d "$1" ]]; then + SAVEIFS=$IFS + IFS=$'\n' + local children=($(find "$1/" -maxdepth 1 -mindepth 1)) + IFS=$SAVEIFS + local dirname=$(basename "$1") + mkdir -p "$target/$dirname" + for child in "${children[@]:-}"; do + if [[ -n "$child" && "$dirname" != *.ext_build_deps ]]; then + ##symlink_to_dir## "$child" "$target/$dirname" + fi + done +else + echo "Can not copy $1" +fi +""" + return FunctionAndCallInfo(text = text) + +def script_prelude(): + return "set -euo pipefail" + +def increment_pkg_config_path(source): + text = """\ +local children=$(find "$1/" -mindepth 1 -name '*.pc') +# assume there is only one directory with pkg config +for child in $children; do + export PKG_CONFIG_PATH="$${PKG_CONFIG_PATH:-}$$:$(dirname $child)" + return +done +""" + return FunctionAndCallInfo(text = text) + +def cat(filepath): + return "cat \"{}\"".format(filepath) + +def redirect_out_err(from_process, to_file): + return from_process + " &> " + to_file + +def assert_script_errors(): + return "set -e" + +def cleanup_function(on_success, on_failure): + text = "\n".join([ + "local ecode=$?", + "if [ $ecode -eq 0 ]; then", + on_success, + "else", + on_failure, + "fi", + ]) + return FunctionAndCallInfo(text = text, call = "trap \"cleanup_function\" EXIT") + +def children_to_path(dir_): + text = """\ +if [ -d {dir_} ]; then + local tools=$(find $EXT_BUILD_DEPS/bin/ -maxdepth 1 -mindepth 1) + for tool in $tools; + do + if [[ -d \"$tool\" ]] || [[ -L \"$tool\" ]]; then + export PATH=$PATH:$tool + fi + done +fi""".format(dir_ = dir_) + return FunctionAndCallInfo(text = text) + +def define_absolute_paths(dir_, abs_path): + return "##replace_in_files## {dir_} {REPLACE_VALUE} {abs_path}".format( + dir_ = dir_, + REPLACE_VALUE = "\\${EXT_BUILD_DEPS}", + abs_path = abs_path, + ) + +def replace_absolute_paths(dir_, abs_path): + return "##replace_in_files## {dir_} {abs_path} {REPLACE_VALUE}".format( + dir_ = dir_, + REPLACE_VALUE = "\\${EXT_BUILD_DEPS}", + abs_path = abs_path, + ) + +def define_sandbox_paths(dir_, abs_path): + return "##replace_in_files## {dir_} {REPLACE_VALUE} {abs_path}".format( + dir_ = dir_, + REPLACE_VALUE = "\\${EXT_BUILD_ROOT}", + abs_path = abs_path, + ) + +def replace_sandbox_paths(dir_, abs_path): + return "##replace_in_files## {dir_} {abs_path} {REPLACE_VALUE}".format( + dir_ = dir_, + REPLACE_VALUE = "\\${EXT_BUILD_ROOT}", + abs_path = abs_path, + ) + +def replace_symlink(file): + return """\ +if [[ -L "{file}" ]]; then + target="$(readlink -f "{file}")" + rm "{file}" && cp -a "${{target}}" "{file}" +fi +""".format(file = file) diff --git a/foreign_cc/private/framework/toolchains/mappings.bzl b/foreign_cc/private/framework/toolchains/mappings.bzl index 31d7f404..83cb5de9 100644 --- a/foreign_cc/private/framework/toolchains/mappings.bzl +++ b/foreign_cc/private/framework/toolchains/mappings.bzl @@ -25,6 +25,12 @@ TOOLCHAIN_MAPPINGS = [ ], file = Label("@rules_foreign_cc//foreign_cc/private/framework/toolchains:linux_commands.bzl"), ), + _toolchain_mapping( + exec_compatible_with = [ + "@platforms//os:freebsd", + ], + file = Label("@rules_foreign_cc//foreign_cc/private/framework/toolchains:freebsd_commands.bzl"), + ), _toolchain_mapping( exec_compatible_with = [ "@platforms//os:windows", diff --git a/foreign_cc/repositories.bzl b/foreign_cc/repositories.bzl index 931d5ea5..ea8a4a71 100644 --- a/foreign_cc/repositories.bzl +++ b/foreign_cc/repositories.bzl @@ -63,9 +63,11 @@ def rules_foreign_cc_dependencies( maybe( http_archive, name = "bazel_skylib", + # `main` as of 2021-10-27 + # Release request: https://github.com/bazelbuild/bazel-skylib/issues/336 urls = [ - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz", - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.1.1/bazel-skylib-1.1.1.tar.gz", + "https://github.com/bazelbuild/bazel-skylib/archive/6e30a77347071ab22ce346b6d20cf8912919f644.zip", ], - sha256 = "c6966ec828da198c5d9adbaa94c05e3a1c7f21bd012a0b29ba8ddbccb2c93b0d", + strip_prefix = "bazel-skylib-6e30a77347071ab22ce346b6d20cf8912919f644", + sha256 = "247361e64b2a85b40cb45b9c071e42433467c6c87546270cbe2672eb9f317b5a", ) diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 648d70a3..1159664f 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -29,10 +29,17 @@ config_setting( visibility = ["//visibility:private"], ) +config_setting( + name = "freebsd", + constraint_values = ["@platforms//os:freebsd"], + visibility = ["//visibility:private"], +) + diff_test( name = "shell_script_inner_fun_test", file1 = ":shell_script_inner_fun", file2 = select({ + ":freebsd": "expected/inner_fun_text_freebsd.txt", ":macos": "expected/inner_fun_text_macos.txt", "//conditions:default": "expected/inner_fun_text.txt", }), @@ -58,6 +65,7 @@ symlink_contents_to_dir_test_rule( diff_test( name = "shell_method_symlink_contents_to_dir_test", file1 = select({ + ":freebsd": "expected/out_symlinked_dirs_freebsd.txt", ":macos": "expected/out_symlinked_dirs_macos.txt", "//conditions:default": "expected/out_symlinked_dirs.txt", }), diff --git a/test/expected/inner_fun_text_freebsd.txt b/test/expected/inner_fun_text_freebsd.txt new file mode 100755 index 00000000..22747a1c --- /dev/null +++ b/test/expected/inner_fun_text_freebsd.txt @@ -0,0 +1,67 @@ +function symlink_contents_to_dir() { +if [[ -z "$1" ]]; then +echo "arg 1 to symlink_contents_to_dir is unexpectedly empty" +exit 1 +fi +if [[ -z "$2" ]]; then +echo "arg 2 to symlink_contents_to_dir is unexpectedly empty" +exit 1 +fi +local target="$2" +mkdir -p "$target" +if [[ -f "$1" ]]; then +symlink_to_dir "$1" "$target" +elif [[ -L "$1" && ! -d "$1" ]]; then +local actual=$(readlink "$1") +symlink_contents_to_dir "$actual" "$target" +elif [[ -d "$1" ]]; then +SAVEIFS=$IFS +IFS=$' +' +local children=($(find "$1/" -maxdepth 1 -mindepth 1)) +IFS=$SAVEIFS +for child in "${children[@]:-}"; do +symlink_to_dir "$child" "$target" +done +fi +} +function symlink_to_dir() { +if [[ -z "$1" ]]; then +echo "arg 1 to symlink_to_dir is unexpectedly empty" +exit 1 +fi +if [[ -z "$2" ]]; then +echo "arg 2 to symlink_to_dir is unexpectedly empty" +exit 1 +fi +local target="$2" +mkdir -p "$target" +if [[ -f "$1" ]]; then +# In order to be able to use `replace_in_files`, we ensure that we create copies of specfieid +# files so updating them is possible. +if [[ "$1" == *.pc || "$1" == *.la || "$1" == *-config || "$1" == *.mk || "$1" == *.cmake ]]; then +dest="$target/$(basename $1)" +cp "$1" "$dest" && chmod +w "$dest" && touch -r "$1" "$dest" +else +ln -s -f "$1" "$target" +fi +elif [[ -L "$1" && ! -d "$1" ]]; then +cp -pR "$1" "$2" +elif [[ -d "$1" ]]; then +SAVEIFS=$IFS +IFS=$' +' +local children=($(find "$1/" -maxdepth 1 -mindepth 1)) +IFS=$SAVEIFS +local dirname=$(basename "$1") +mkdir -p "$target/$dirname" +for child in "${children[@]:-}"; do +if [[ -n "$child" && "$dirname" != *.ext_build_deps ]]; then +symlink_to_dir "$child" "$target/$dirname" +fi +done +else +echo "Can not copy $1" +fi +} +symlink_contents_to_dir $SOURCE_DIR $TARGET_DIR \ No newline at end of file diff --git a/test/expected/out_symlinked_dirs_freebsd.txt b/test/expected/out_symlinked_dirs_freebsd.txt new file mode 100644 index 00000000..8486dbfb --- /dev/null +++ b/test/expected/out_symlinked_dirs_freebsd.txt @@ -0,0 +1,2 @@ +header1.h +header2.h