diff --git a/cc/defs.bzl b/cc/defs.bzl index 44f62752..72f7a0d7 100644 --- a/cc/defs.bzl +++ b/cc/defs.bzl @@ -10,6 +10,8 @@ """Swift wrappers for native cc rules.""" +load(":utils.bzl", "construct_local_include") + # Name for a unit test UNIT = "unit" @@ -74,6 +76,9 @@ def _common_c_opts(nocopts, pedantic = False): return copts +def _construct_local_includes(local_includes): + return [construct_local_include(path) for path in local_includes] + def swift_cc_library(**kwargs): """Wraps cc_library to enforce standards for a production library. @@ -85,13 +90,21 @@ def swift_cc_library(**kwargs): Args: **kwargs: See https://bazel.build/reference/be/c-cpp#cc_library - An additional attribute nocopts is supported. This - attribute takes a list of flags to remove from the - default compiler options. Use judiciously. + The following additional attributes are supported: + + local_includes: List of local (non-public) include paths. Prefer + this to passing local includes using copts. Paths are expected to + be relative to the package this macro is called from. + + nocopts: List of flags to remove from the default compile + options. Use judiciously. """ + local_includes = _construct_local_includes(kwargs.pop("local_includes", [])) + nocopts = kwargs.pop("nocopts", []) # pop because nocopts is a deprecated cc* attr. copts = _common_c_opts(nocopts, pedantic = True) + copts = local_includes + copts kwargs["copts"] = (kwargs["copts"] if "copts" in kwargs else []) + copts native.cc_library(**kwargs) @@ -108,13 +121,21 @@ def swift_cc_tool_library(**kwargs): Args: **kwargs: See https://bazel.build/reference/be/c-cpp#cc_library - An additional attribute nocopts is supported. This - attribute takes a list of flags to remove from the - default compiler options. Use judiciously. + The following additional attributes are supported: + + local_includes: List of local (non-public) include paths. Prefer + this to passing local includes using copts. Paths are expected to + be relative to the package this macro is called from. + + nocopts: List of flags to remove from the default compile + options. Use judiciously. """ + local_includes = _construct_local_includes(kwargs.pop("local_includes", [])) + nocopts = kwargs.pop("nocopts", []) copts = _common_c_opts(nocopts, pedantic = False) + copts = local_includes + copts kwargs["copts"] = (kwargs["copts"] if "copts" in kwargs else []) + copts native.cc_library(**kwargs) @@ -130,13 +151,21 @@ def swift_cc_binary(**kwargs): Args: **kwargs: See https://bazel.build/reference/be/c-cpp#cc_binary - An additional attribute nocopts is supported. This - attribute takes a list of flags to remove from the - default compiler options. Use judiciously. + The following additional attributes are supported: + + local_includes: List of local (non-public) include paths. Prefer + this to passing local includes using copts. Paths are expected to + be relative to the package this macro is called from. + + nocopts: List of flags to remove from the default compile + options. Use judiciously. """ + local_includes = _construct_local_includes(kwargs.pop("local_includes", [])) + nocopts = kwargs.pop("nocopts", []) copts = _common_c_opts(nocopts, pedantic = True) + copts = local_includes + copts kwargs["copts"] = (kwargs["copts"] if "copts" in kwargs else []) + copts native.cc_binary(**kwargs) @@ -153,9 +182,14 @@ def swift_cc_tool(**kwargs): Args: **kwargs: See https://bazel.build/reference/be/c-cpp#cc_binary - An additional attribute nocopts is supported. This - attribute takes a list of flags to remove from the - default compiler options. Use judiciously. + The following additional attributes are supported: + + local_includes: List of local (non-public) include paths. Prefer + this to passing local includes using copts. Paths are expected to + be relative to the package this macro is called from. + + nocopts: List of flags to remove from the default compile + options. Use judiciously. """ nocopts = kwargs.pop("nocopts", []) @@ -169,7 +203,16 @@ def swift_cc_test_library(**kwargs): Args: **kwargs: See https://bazel.build/reference/be/c-cpp#cc_test + + The following additional attributes are supported: + + local_includes: List of local (non-public) include paths. Prefer + this to passing local includes using copts. Paths are expected to + be relative to the package this macro is called from. """ + local_includes = _construct_local_includes(kwargs.pop("local_includes", [])) + + kwargs["copts"] = (kwargs["copts"] if "copts" in kwargs else []) + local_includes native.cc_library(**kwargs) def swift_cc_test(name, type, **kwargs): @@ -183,11 +226,20 @@ def swift_cc_test(name, type, **kwargs): these test types seperately: `bazel test --test_tag_filters=unit //...` **kwargs: See https://bazel.build/reference/be/c-cpp#cc_test + + The following additional attributes are supported: + + local_includes: List of local (non-public) include paths. Prefer + this to passing local includes using copts. Paths are expected to + be relative to the package this macro is called from. """ if not (type == UNIT or type == INTEGRATION): fail("The 'type' attribute must be either UNIT or INTEGRATION") + local_includes = _construct_local_includes(kwargs.pop("local_includes", [])) + + kwargs["copts"] = (kwargs["copts"] if "copts" in kwargs else []) + local_includes kwargs["name"] = name kwargs["tags"] = (kwargs["tags"] if "tags" in kwargs else []) + [type] native.cc_test(**kwargs) diff --git a/cc/utils.bzl b/cc/utils.bzl new file mode 100644 index 00000000..b31bf8ab --- /dev/null +++ b/cc/utils.bzl @@ -0,0 +1,35 @@ +# Copyright (C) 2022 Swift Navigation Inc. +# Contact: Swift Navigation +# +# This source is subject to the license found in the file 'LICENSE' which must +# be be distributed together with this source. All other rights reserved. +# +# THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +# EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE. + +def construct_local_include(path): + """Helper to correctly set up local (non-public) include paths. + + When a bazel workspace is consumed externally, (i.e. via local_repository), + its sources are placed under /external//. This + typically breaks local include paths defined using -I. + + This macro ensures that the include path is constructed correctly both when + building a workpace standalone, and externally. + + Args: + path: The include path relative to the package this macro is called from + + Use the special argument $(GENDIR) to construct an include path for + any generated files the build depends on. Assumes these files are + not generated into a subdirectory. + """ + root = Label(native.repository_name() + "//:WORKSPACE").workspace_root or "." + package = native.package_name() + + # Generated files are placed in $(GENDIR)/external/ + if path == "$(GENDIR)": + return "-I" + path + "/" + root + "/" + package + "/" + else: + return "-I" + root + "/" + package + "/" + path + "/"