diff --git a/WORKSPACE b/WORKSPACE index ac387ff8..f4d6249c 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -3,15 +3,15 @@ workspace(name = "rules_foreign_cc") all_content = """filegroup(name = "all", srcs = glob(["**"]), visibility = ["//visibility:public"])""" new_http_archive( - name = "bazel_skylib", - urls = [ - "https://github.com/bazelbuild/bazel-skylib/archive/0.5.0.tar.gz", - ], - strip_prefix= "bazel-skylib-0.5.0", - sha256 = "b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f", - type = "tar.gz", - build_file_content = all_content, - ) + name = "bazel_skylib", + build_file_content = all_content, + sha256 = "b5f6abe419da897b7901f90cbab08af958b97a8f3575b0d3dd062ac7ce78541f", + strip_prefix = "bazel-skylib-0.5.0", + type = "tar.gz", + urls = [ + "https://github.com/bazelbuild/bazel-skylib/archive/0.5.0.tar.gz", + ], +) new_http_archive( name = "libevent", @@ -21,21 +21,59 @@ new_http_archive( ) new_http_archive( - name = "zlib", - urls = [ - "https://zlib.net/zlib-1.2.11.tar.xz", - ], - strip_prefix= "zlib-1.2.11", - sha256 = "4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066", - build_file_content = all_content, - ) + name = "zlib", + build_file_content = all_content, + sha256 = "4ff941449631ace0d4d203e3483be9dbc9da454084111f97ea0a2114e19bf066", + strip_prefix = "zlib-1.2.11", + urls = [ + "https://zlib.net/zlib-1.2.11.tar.xz", + ], +) new_http_archive( - name = "libpng", - urls = [ - "http://ftp-osl.osuosl.org/pub/libpng/src/libpng16/libpng-1.6.34.tar.xz", - ], - strip_prefix= "libpng-1.6.34", - sha256 = "2f1e960d92ce3b3abd03d06dfec9637dfbd22febf107a536b44f7a47c60659f6", - build_file_content = all_content, - ) \ No newline at end of file + name = "libpng", + build_file_content = all_content, + sha256 = "2f1e960d92ce3b3abd03d06dfec9637dfbd22febf107a536b44f7a47c60659f6", + strip_prefix = "libpng-1.6.34", + urls = [ + "http://ftp-osl.osuosl.org/pub/libpng/src/libpng16/libpng-1.6.34.tar.xz", + ], +) + +new_http_archive( + name = "org_linaro_components_toolchain_gcc_5_3_1", + build_file = "framework_example/cmake_cross/compilers/linaro_linux_gcc_5.3.1.BUILD", + strip_prefix = "gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf", + url = "https://bazel-mirror.storage.googleapis.com/releases.linaro.org/components/toolchain/binaries/latest-5/arm-linux-gnueabihf/gcc-linaro-5.3.1-2016.05-x86_64_arm-linux-gnueabihf.tar.xz", +) + +http_archive( + name = "bazel_toolchains", + sha256 = "259ec05a457bc93aec2aee7e4e67fb4bc1724a183b67baaf5dd6a08be6d6a84a", + strip_prefix = "bazel-toolchains-e76b1031eba14c16d72f5837ae7cb7630a2322e2", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/e76b1031eba14c16d72f5837ae7cb7630a2322e2.tar.gz", + "https://github.com/bazelbuild/bazel-toolchains/archive/e76b1031eba14c16d72f5837ae7cb7630a2322e2.tar.gz", + ], +) + +android_sdk_repository( + name = "androidsdk", +) + +android_ndk_repository( + name = "androidndk", +) + +# Google Maven Repository +GMAVEN_TAG = "20180625-1" + +http_archive( + name = "gmaven_rules", + strip_prefix = "gmaven_rules-%s" % GMAVEN_TAG, + url = "https://github.com/bazelbuild/gmaven_rules/archive/%s.tar.gz" % GMAVEN_TAG, +) + +load("@gmaven_rules//:gmaven.bzl", "gmaven_rules") + +gmaven_rules() diff --git a/framework_example/cmake/BUILD b/framework_example/cmake/BUILD index 5d39168c..fd96a457 100644 --- a/framework_example/cmake/BUILD +++ b/framework_example/cmake/BUILD @@ -25,7 +25,7 @@ cc_binary( ) cc_binary( - name = "test_zlib", + name = "zlib_usage_example", srcs = ["zlib-example.cpp"], - deps = ["libz"], + deps = [":libz"], ) diff --git a/framework_example/cmake_android/AndroidManifest.xml b/framework_example/cmake_android/AndroidManifest.xml new file mode 100644 index 00000000..8af06726 --- /dev/null +++ b/framework_example/cmake_android/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/framework_example/cmake_android/BUILD b/framework_example/cmake_android/BUILD new file mode 100644 index 00000000..148db3a3 --- /dev/null +++ b/framework_example/cmake_android/BUILD @@ -0,0 +1,38 @@ +load("//tools/build_defs:cmake.bzl", "cmake_external") +load("@gmaven_rules//:defs.bzl", "gmaven_artifact") + +cmake_external( + name = "libhello", + additional_tools = [ + "@androidndk//:files", + ], + lib_source = "//framework_example/cmake_hello_world_lib:srcs", +) + +cc_library( + name = "hello_lib_usage_example", + srcs = ["hello_lib-example.cpp"], + linkstatic = True, + deps = [":libhello"], + alwayslink = True, +) + +android_library( + name = "lib", + srcs = ["java/com/example/android/bazel/MainActivity.java"], + custom_package = "com.example.android.bazel", + manifest = "LibraryManifest.xml", + resource_files = glob(["res/**/*"]), + deps = [ + ":hello_lib_usage_example", + gmaven_artifact("com.android.support:appcompat-v7:aar:26.1.0"), + gmaven_artifact("com.android.support.constraint:constraint-layout:aar:1.1.2"), + ], +) + +android_binary( + name = "app", + custom_package = "com.example.android.bazel", + manifest = "AndroidManifest.xml", + deps = [":lib"], +) diff --git a/framework_example/cmake_android/LibraryManifest.xml b/framework_example/cmake_android/LibraryManifest.xml new file mode 100644 index 00000000..f6724fd1 --- /dev/null +++ b/framework_example/cmake_android/LibraryManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/framework_example/cmake_android/cpp/native-lib.cpp b/framework_example/cmake_android/cpp/native-lib.cpp new file mode 100644 index 00000000..b28dfc6c --- /dev/null +++ b/framework_example/cmake_android/cpp/native-lib.cpp @@ -0,0 +1,13 @@ +#include +#include + +extern "C" +JNIEXPORT jstring + +JNICALL +Java_com_example_android_bazel_MainActivity_stringFromJNI( + JNIEnv *env, + jobject /* this */) { + std::string hello = "Hello from C++"; + return env->NewStringUTF(hello.c_str()); +} diff --git a/framework_example/cmake_android/hello_lib-example.cpp b/framework_example/cmake_android/hello_lib-example.cpp new file mode 100644 index 00000000..c42ed6eb --- /dev/null +++ b/framework_example/cmake_android/hello_lib-example.cpp @@ -0,0 +1,8 @@ +#include +#include "hello.h" + +int main(int argc, char* argv[]) +{ + hello_func(); + return 0; +} \ No newline at end of file diff --git a/framework_example/cmake_android/java/com/example/android/bazel/MainActivity.java b/framework_example/cmake_android/java/com/example/android/bazel/MainActivity.java new file mode 100644 index 00000000..cd79f132 --- /dev/null +++ b/framework_example/cmake_android/java/com/example/android/bazel/MainActivity.java @@ -0,0 +1,28 @@ +package framework_example.cmake_android.java.com.example.android.bazel; + +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.widget.TextView; + +public class MainActivity extends AppCompatActivity { + + static { + System.loadLibrary("app"); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // setContentView(R.layout.activity_main); + // + // // Example of a call to a native method + // TextView tv = (TextView) findViewById(R.id.sample_text); + // tv.setText(stringFromJNI()); + } + + /** + * A native method that is implemented by the 'native-lib' native library, + * which is packaged with this application. + */ + public native String stringFromJNI(); +} diff --git a/framework_example/cmake_android/res/drawable-v24/ic_launcher_foreground.xml b/framework_example/cmake_android/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 00000000..c7bd21db --- /dev/null +++ b/framework_example/cmake_android/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/framework_example/cmake_android/res/drawable/ic_launcher_background.xml b/framework_example/cmake_android/res/drawable/ic_launcher_background.xml new file mode 100644 index 00000000..d5fccc53 --- /dev/null +++ b/framework_example/cmake_android/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/framework_example/cmake_android/res/layout/activity_main.xml b/framework_example/cmake_android/res/layout/activity_main.xml new file mode 100644 index 00000000..367bd1ab --- /dev/null +++ b/framework_example/cmake_android/res/layout/activity_main.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/framework_example/cmake_android/res/mipmap-anydpi-v26/ic_launcher.xml b/framework_example/cmake_android/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/framework_example/cmake_android/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/framework_example/cmake_android/res/mipmap-anydpi-v26/ic_launcher_round.xml b/framework_example/cmake_android/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 00000000..eca70cfe --- /dev/null +++ b/framework_example/cmake_android/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/framework_example/cmake_android/res/mipmap-hdpi/ic_launcher.png b/framework_example/cmake_android/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 00000000..a2f59082 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-hdpi/ic_launcher.png differ diff --git a/framework_example/cmake_android/res/mipmap-hdpi/ic_launcher_round.png b/framework_example/cmake_android/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 00000000..1b523998 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/framework_example/cmake_android/res/mipmap-mdpi/ic_launcher.png b/framework_example/cmake_android/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 00000000..ff10afd6 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-mdpi/ic_launcher.png differ diff --git a/framework_example/cmake_android/res/mipmap-mdpi/ic_launcher_round.png b/framework_example/cmake_android/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 00000000..115a4c76 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/framework_example/cmake_android/res/mipmap-xhdpi/ic_launcher.png b/framework_example/cmake_android/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 00000000..dcd3cd80 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/framework_example/cmake_android/res/mipmap-xhdpi/ic_launcher_round.png b/framework_example/cmake_android/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 00000000..459ca609 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/framework_example/cmake_android/res/mipmap-xxhdpi/ic_launcher.png b/framework_example/cmake_android/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 00000000..8ca12fe0 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/framework_example/cmake_android/res/mipmap-xxhdpi/ic_launcher_round.png b/framework_example/cmake_android/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..8e19b410 Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/framework_example/cmake_android/res/mipmap-xxxhdpi/ic_launcher.png b/framework_example/cmake_android/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 00000000..b824ebdd Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/framework_example/cmake_android/res/mipmap-xxxhdpi/ic_launcher_round.png b/framework_example/cmake_android/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 00000000..4c19a13c Binary files /dev/null and b/framework_example/cmake_android/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/framework_example/cmake_android/res/values/colors.xml b/framework_example/cmake_android/res/values/colors.xml new file mode 100644 index 00000000..3ab3e9cb --- /dev/null +++ b/framework_example/cmake_android/res/values/colors.xml @@ -0,0 +1,6 @@ + + + #3F51B5 + #303F9F + #FF4081 + diff --git a/framework_example/cmake_android/res/values/strings.xml b/framework_example/cmake_android/res/values/strings.xml new file mode 100644 index 00000000..a73177f1 --- /dev/null +++ b/framework_example/cmake_android/res/values/strings.xml @@ -0,0 +1,3 @@ + + Built By Bazel + diff --git a/framework_example/cmake_android/res/values/styles.xml b/framework_example/cmake_android/res/values/styles.xml new file mode 100644 index 00000000..5885930d --- /dev/null +++ b/framework_example/cmake_android/res/values/styles.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/framework_example/cmake_android/zlib-example.cpp b/framework_example/cmake_android/zlib-example.cpp new file mode 100644 index 00000000..19e7a057 --- /dev/null +++ b/framework_example/cmake_android/zlib-example.cpp @@ -0,0 +1,80 @@ +// Copied from https://gist.github.com/arq5x/5315739 for test purposes + +#include +#include // for strlen +#include +#include "zlib.h" + +// adapted from: http://stackoverflow.com/questions/7540259/deflate-and-inflate-zlib-h-in-c +int main(int argc, char* argv[]) +{ + // original string len = 36 + char a[50] = "Hello Hello Hello Hello Hello Hello!"; + + // placeholder for the compressed (deflated) version of "a" + char b[50]; + + // placeholder for the UNcompressed (inflated) version of "b" + char c[50]; + + + printf("Uncompressed size is: %lu\n", strlen(a)); + printf("Uncompressed string is: %s\n", a); + + + printf("\n----------\n\n"); + + // STEP 1. + // deflate a into b. (that is, compress a into b) + + // zlib struct + z_stream defstream; + defstream.zalloc = Z_NULL; + defstream.zfree = Z_NULL; + defstream.opaque = Z_NULL; + // setup "a" as the input and "b" as the compressed output + defstream.avail_in = (uInt)strlen(a)+1; // size of input, string + terminator + defstream.next_in = (Bytef *)a; // input char array + defstream.avail_out = (uInt)sizeof(b); // size of output + defstream.next_out = (Bytef *)b; // output char array + + // the actual compression work. + deflateInit(&defstream, Z_BEST_COMPRESSION); + deflate(&defstream, Z_FINISH); + deflateEnd(&defstream); + + // This is one way of getting the size of the output + printf("Compressed size is: %lu\n", strlen(b)); + printf("Compressed string is: %s\n", b); + + + printf("\n----------\n\n"); + + + // STEP 2. + // inflate b into c + // zlib struct + z_stream infstream; + infstream.zalloc = Z_NULL; + infstream.zfree = Z_NULL; + infstream.opaque = Z_NULL; + // setup "b" as the input and "c" as the compressed output + infstream.avail_in = (uInt)((char*)defstream.next_out - b); // size of input + infstream.next_in = (Bytef *)b; // input char array + infstream.avail_out = (uInt)sizeof(c); // size of output + infstream.next_out = (Bytef *)c; // output char array + + // the actual DE-compression work. + inflateInit(&infstream); + inflate(&infstream, Z_NO_FLUSH); + inflateEnd(&infstream); + + printf("Uncompressed size is: %lu\n", strlen(c)); + printf("Uncompressed string is: %s\n", c); + + + // make sure uncompressed is exactly equal to original. + assert(strcmp(a,c)==0); + + return 0; +} \ No newline at end of file diff --git a/framework_example/cmake_hello_world_lib/BUILD b/framework_example/cmake_hello_world_lib/BUILD new file mode 100644 index 00000000..a4b04b80 --- /dev/null +++ b/framework_example/cmake_hello_world_lib/BUILD @@ -0,0 +1,8 @@ +# example code is taken from https://github.com/Akagi201/learning-cmake/tree/master/hello-world-lib +# for test only + +filegroup( + name = "srcs", + srcs = glob(["**"]), + visibility = ["//visibility:public"] +) diff --git a/framework_example/cmake_hello_world_lib/CMakeLists.txt b/framework_example/cmake_hello_world_lib/CMakeLists.txt new file mode 100644 index 00000000..4e1188e9 --- /dev/null +++ b/framework_example/cmake_hello_world_lib/CMakeLists.txt @@ -0,0 +1,8 @@ +# taken from https://github.com/Akagi201/learning-cmake/tree/master/hello-world-lib +# for test only + +cmake_minimum_required(VERSION 2.8.4) + +project(hellolib) + +add_subdirectory(src) \ No newline at end of file diff --git a/framework_example/cmake_hello_world_lib/src/CMakeLists.txt b/framework_example/cmake_hello_world_lib/src/CMakeLists.txt new file mode 100644 index 00000000..d4226ca3 --- /dev/null +++ b/framework_example/cmake_hello_world_lib/src/CMakeLists.txt @@ -0,0 +1,24 @@ +# taken from https://github.com/Akagi201/learning-cmake/tree/master/hello-world-lib +# for test only + +cmake_minimum_required(VERSION 2.8.4) + +message("CMAKE_CXX_CREATE_STATIC_LIBRARY: " CMAKE_CXX_CREATE_STATIC_LIBRARY) + +set(LIBHELLO_SRC hello.c) + +add_library(hello_dynamic SHARED ${LIBHELLO_SRC}) +add_library(hello_static STATIC ${LIBHELLO_SRC}) + +set_target_properties(hello_dynamic PROPERTIES OUTPUT_NAME "hello") +set_target_properties(hello_dynamic PROPERTIES VERSION 1.2 SOVERSION 1) + +set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello") + +set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) + +install(TARGETS hello_dynamic hello_static + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + +install(FILES hello.h DESTINATION include) \ No newline at end of file diff --git a/framework_example/cmake_hello_world_lib/src/hello.c b/framework_example/cmake_hello_world_lib/src/hello.c new file mode 100644 index 00000000..740ba68c --- /dev/null +++ b/framework_example/cmake_hello_world_lib/src/hello.c @@ -0,0 +1,7 @@ +#include "hello.h" + +void hello_func(void) { + printf("Hello World!\n"); + + return; +} \ No newline at end of file diff --git a/framework_example/cmake_hello_world_lib/src/hello.h b/framework_example/cmake_hello_world_lib/src/hello.h new file mode 100644 index 00000000..857e1e24 --- /dev/null +++ b/framework_example/cmake_hello_world_lib/src/hello.h @@ -0,0 +1,8 @@ +#ifndef HELLO_H_ +#define HELLO_H_ (1) + +#include + +void hello_func(void); + +#endif \ No newline at end of file diff --git a/tools/build_defs/cc_linking_util.bzl b/tools/build_defs/cc_linking_util.bzl deleted file mode 100644 index c05eb088..00000000 --- a/tools/build_defs/cc_linking_util.bzl +++ /dev/null @@ -1,227 +0,0 @@ -""" Defines create_linking_info, which wraps passed libraries into CcLinkingInfo -""" - -load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") - -LibrariesToLinkInfo = provider( - doc = "Libraries to be wrapped into CcLinkingInfo", - fields = dict( - static_libraries = "Static library files, optional", - shared_libraries = "Dynamic library files, optional", - interface_libraries = "Interface library files, optional", -)) - -def _to_list(element): - if element == None: - return [] - else: - return [element] - -def _to_depset(element): - if element == None: - return depset() - return depset(element) - -def _perform_error_checks( - system_provided, - shared_library_artifacts, - interface_library_artifacts, - targets_windows): - # If the shared library will be provided by system during runtime, users are not supposed to - # specify shared_library. - if system_provided and shared_library_artifacts != None: - fail("'shared_library' shouldn't be specified when 'system_provided' is true") - - # If a shared library won't be provided by system during runtime and we are linking the shared - # library through interface library, the shared library must be specified. - if (not system_provided and shared_library_artifacts == None and - interface_library_artifacts != None): - fail("'shared_library' should be specified when 'system_provided' is false") - - if targets_windows and shared_library_artifacts != None: - fail("'interface library' must be specified when using cc_import for " + - "shared library on Windows") - -def _build_static_library_to_link(ctx, library): - if library == None: - fail("Parameter 'static_library_artifact' cannot be None") - - static_library_category = None - if ctx.attr.alwayslink: - static_library_category = "alwayslink_static_library" - else: - static_library_category = "static_library" - - return cc_common.create_library_to_link( - ctx = ctx, - library = library, - artifact_category = static_library_category, - ) - -def _build_shared_library_to_link(ctx, library, cc_toolchain, targets_windows): - if library == None: - fail("Parameter 'shared_library_artifact' cannot be None") - - if targets_windows: - return cc_common.create_library_to_link( - ctx = ctx, - library = library, - artifact_category = "dynamic_library", - ) - else: - return cc_common.create_symlink_library_to_link( - ctx = ctx, - cc_toolchain = cc_toolchain, - library = library, - ) - -def _build_interface_library_to_link(ctx, library, cc_toolchain, targets_windows): - if library == None: - fail("Parameter 'interface_library_artifact' cannot be None") - - if targets_windows: - return cc_common.create_library_to_link( - ctx = ctx, - library = library, - artifact_category = "interface_library", - ) - else: - return cc_common.create_symlink_library_to_link( - ctx = ctx, - cc_toolchain = cc_toolchain, - library = library, - ) - -# we could possibly take a decision about linking interface/shared library beased on each library name -# (usefull for the case when multiple output targets are provided) -def _build_libraries_to_link_and_runtime_artifact(ctx, files, cc_toolchain, targets_windows): - static_libraries = [_build_static_library_to_link(ctx, lib) for lib in (files.static_libraries or [])] - - shared_libraries = [] - runtime_artifacts = [] - if files.shared_libraries != None: - for lib in files.shared_libraries: - shared_library += _build_shared_library_to_link(ctx, lib, cc_toolchain, targets_windows) - runtime_artifact += shared_library.artifact() - - interface_libraries = [] - if files.interface_libraries != None: - for lib in files.interface_libraries: - interface_libraries += _build_interface_library_to_link(ctx, lib, cc_toolchain, targets_windows) - - dynamic_libraries_for_linking = None - if len(interface_libraries) > 0: - dynamic_libraries_for_linking = interface_libraries - else: - dynamic_libraries_for_linking = shared_libraries - - return {"static_libraries": static_libraries, - "dynamic_libraries": dynamic_libraries_for_linking, - "runtime_artifacts": runtime_artifacts} - -def _build_cc_link_params( - ctx, - user_link_flags, - static_libraries, - dynamic_libraries, - runtime_artifacts): - static_shared = None - static_no_shared = None - if static_libraries != None and len(static_libraries) > 0: - static_shared = cc_common.create_cc_link_params( - ctx = ctx, - user_link_flags = user_link_flags, - libraries_to_link = _to_depset(static_libraries), - ) - static_no_shared = cc_common.create_cc_link_params( - ctx = ctx, - libraries_to_link = _to_depset(static_libraries), - ) - else: - static_shared = cc_common.create_cc_link_params( - ctx = ctx, - user_link_flags = user_link_flags, - libraries_to_link = _to_depset(dynamic_libraries), - dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), - ) - static_no_shared = cc_common.create_cc_link_params( - ctx = ctx, - libraries_to_link = _to_depset(dynamic_libraries), - dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), - ) - - no_static_shared = None - no_static_no_shared = None - if dynamic_libraries != None and len(dynamic_libraries) > 0: - no_static_shared = cc_common.create_cc_link_params( - ctx = ctx, - user_link_flags = user_link_flags, - libraries_to_link = _to_depset(dynamic_libraries), - dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), - ) - no_static_no_shared = cc_common.create_cc_link_params( - ctx = ctx, - libraries_to_link = _to_depset(dynamic_libraries), - dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), - ) - else: - no_static_shared = cc_common.create_cc_link_params( - ctx = ctx, - user_link_flags = user_link_flags, - libraries_to_link = _to_depset(static_libraries), - ) - no_static_no_shared = cc_common.create_cc_link_params( - ctx = ctx, - libraries_to_link = _to_depset(static_libraries), - ) - - return {"static_mode_params_for_dynamic_library": static_shared, - "static_mode_params_for_executable": static_no_shared, - "dynamic_mode_params_for_dynamic_library": no_static_shared, - "dynamic_mode_params_for_executable": no_static_no_shared} - -def targets_windows(ctx, cc_toolchain): - """ Returns true if build is targeting Windows - Args: - ctx - rule context - cc_toolchain - optional - Cc toolchain - """ - toolchain = cc_toolchain if cc_toolchain else find_cpp_toolchain(ctx) - feature_configuration = cc_common.configure_features( - cc_toolchain = toolchain, - requested_features = ctx.features, - unsupported_features = ctx.disabled_features, - ) - - return cc_common.is_enabled( - feature_configuration = feature_configuration, - feature_name = "targets_windows", - ) - -def create_linking_info(ctx, user_link_flags, files): - """ Creates CcLinkingInfo for the passed user link options and libraries. - Args: - ctx - rule context - user_link_flags - (list of strings) link optins, provided by user - files - (LibrariesToLink) provider with the library files - """ - cc_toolchain = find_cpp_toolchain(ctx) - for_windows = targets_windows(ctx, cc_toolchain) - - _perform_error_checks( - False, - files.shared_libraries, - files.interface_libraries, - for_windows, - ) - - artifacts = _build_libraries_to_link_and_runtime_artifact( - ctx, - files, - cc_toolchain, - for_windows, - ) - - link_params = _build_cc_link_params(ctx, user_link_flags, **artifacts) - - return CcLinkingInfo(**link_params) diff --git a/tools/build_defs/cc_toolchain_util.bzl b/tools/build_defs/cc_toolchain_util.bzl new file mode 100644 index 00000000..ba906ffd --- /dev/null +++ b/tools/build_defs/cc_toolchain_util.bzl @@ -0,0 +1,397 @@ +""" Defines create_linking_info, which wraps passed libraries into CcLinkingInfo +""" + +load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") +load( + "@bazel_tools//tools/build_defs/cc:action_names.bzl", + "ASSEMBLE_ACTION_NAME", + "CPP_COMPILE_ACTION_NAME", + "CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME", + "CPP_LINK_EXECUTABLE_ACTION_NAME", + "CPP_LINK_STATIC_LIBRARY_ACTION_NAME", + "C_COMPILE_ACTION_NAME", +) + +LibrariesToLinkInfo = provider( + doc = "Libraries to be wrapped into CcLinkingInfo", + fields = dict( + static_libraries = "Static library files, optional", + shared_libraries = "Shared library files, optional", + interface_libraries = "Interface library files, optional", + ), +) + +CxxToolsInfo = provider( + doc = "Paths to the C/C++ tools, taken from the toolchain", + fields = dict( + cc = "C compiler", + cxx = "C++ compiler", + cxx_linker_static = "C++ linker to link static library", + cxx_linker_executable = "C++ linker to link executable", + ), +) + +CxxFlagsInfo = provider( + doc = "Flags for the C/C++ tools, taken from the toolchain", + fields = dict( + cc = "C compiler flags", + cxx = "C++ compiler flags", + cxx_linker_shared = "C++ linker flags when linking shared library", + cxx_linker_static = "C++ linker flags when linking static library", + cxx_linker_executable = "C++ linker flags when linking executable", + assemble = "Assemble flags", + ), +) + +def _to_list(element): + if element == None: + return [] + else: + return [element] + +def _to_depset(element): + if element == None: + return depset() + return depset(element) + +def _perform_error_checks( + system_provided, + shared_library_artifacts, + interface_library_artifacts, + targets_windows): + # If the shared library will be provided by system during runtime, users are not supposed to + # specify shared_library. + if system_provided and shared_library_artifacts != None: + fail("'shared_library' shouldn't be specified when 'system_provided' is true") + + # If a shared library won't be provided by system during runtime and we are linking the shared + # library through interface library, the shared library must be specified. + if (not system_provided and shared_library_artifacts == None and + interface_library_artifacts != None): + fail("'shared_library' should be specified when 'system_provided' is false") + + if targets_windows and shared_library_artifacts != None: + fail("'interface library' must be specified when using cc_import for " + + "shared library on Windows") + +def _build_static_library_to_link(ctx, library): + if library == None: + fail("Parameter 'static_library_artifact' cannot be None") + + static_library_category = None + if ctx.attr.alwayslink: + static_library_category = "alwayslink_static_library" + else: + static_library_category = "static_library" + + return cc_common.create_library_to_link( + ctx = ctx, + library = library, + artifact_category = static_library_category, + ) + +def _build_shared_library_to_link(ctx, library, cc_toolchain, targets_windows): + if library == None: + fail("Parameter 'shared_library_artifact' cannot be None") + + if targets_windows: + return cc_common.create_library_to_link( + ctx = ctx, + library = library, + artifact_category = "dynamic_library", + ) + else: + return cc_common.create_symlink_library_to_link( + ctx = ctx, + cc_toolchain = cc_toolchain, + library = library, + ) + +def _build_interface_library_to_link(ctx, library, cc_toolchain, targets_windows): + if library == None: + fail("Parameter 'interface_library_artifact' cannot be None") + + if targets_windows: + return cc_common.create_library_to_link( + ctx = ctx, + library = library, + artifact_category = "interface_library", + ) + else: + return cc_common.create_symlink_library_to_link( + ctx = ctx, + cc_toolchain = cc_toolchain, + library = library, + ) + +# we could possibly take a decision about linking interface/shared library beased on each library name +# (usefull for the case when multiple output targets are provided) +def _build_libraries_to_link_and_runtime_artifact(ctx, files, cc_toolchain, targets_windows): + static_libraries = [_build_static_library_to_link(ctx, lib) for lib in (files.static_libraries or [])] + + shared_libraries = [] + runtime_artifacts = [] + if files.shared_libraries != None: + for lib in files.shared_libraries: + shared_library += _build_shared_library_to_link(ctx, lib, cc_toolchain, targets_windows) + runtime_artifact += shared_library.artifact() + + interface_libraries = [] + if files.interface_libraries != None: + for lib in files.interface_libraries: + interface_libraries += _build_interface_library_to_link(ctx, lib, cc_toolchain, targets_windows) + + dynamic_libraries_for_linking = None + if len(interface_libraries) > 0: + dynamic_libraries_for_linking = interface_libraries + else: + dynamic_libraries_for_linking = shared_libraries + + return { + "static_libraries": static_libraries, + "dynamic_libraries": dynamic_libraries_for_linking, + "runtime_artifacts": runtime_artifacts, + } + +def _build_cc_link_params( + ctx, + user_link_flags, + static_libraries, + dynamic_libraries, + runtime_artifacts): + static_shared = None + static_no_shared = None + if static_libraries != None and len(static_libraries) > 0: + static_shared = cc_common.create_cc_link_params( + ctx = ctx, + user_link_flags = user_link_flags, + libraries_to_link = _to_depset(static_libraries), + ) + static_no_shared = cc_common.create_cc_link_params( + ctx = ctx, + libraries_to_link = _to_depset(static_libraries), + ) + else: + static_shared = cc_common.create_cc_link_params( + ctx = ctx, + user_link_flags = user_link_flags, + libraries_to_link = _to_depset(dynamic_libraries), + dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), + ) + static_no_shared = cc_common.create_cc_link_params( + ctx = ctx, + libraries_to_link = _to_depset(dynamic_libraries), + dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), + ) + + no_static_shared = None + no_static_no_shared = None + if dynamic_libraries != None and len(dynamic_libraries) > 0: + no_static_shared = cc_common.create_cc_link_params( + ctx = ctx, + user_link_flags = user_link_flags, + libraries_to_link = _to_depset(dynamic_libraries), + dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), + ) + no_static_no_shared = cc_common.create_cc_link_params( + ctx = ctx, + libraries_to_link = _to_depset(dynamic_libraries), + dynamic_libraries_for_runtime = _to_depset(runtime_artifacts), + ) + else: + no_static_shared = cc_common.create_cc_link_params( + ctx = ctx, + user_link_flags = user_link_flags, + libraries_to_link = _to_depset(static_libraries), + ) + no_static_no_shared = cc_common.create_cc_link_params( + ctx = ctx, + libraries_to_link = _to_depset(static_libraries), + ) + + return { + "static_mode_params_for_dynamic_library": static_shared, + "static_mode_params_for_executable": static_no_shared, + "dynamic_mode_params_for_dynamic_library": no_static_shared, + "dynamic_mode_params_for_executable": no_static_no_shared, + } + +def targets_windows(ctx, cc_toolchain): + """ Returns true if build is targeting Windows + Args: + ctx - rule context + cc_toolchain - optional - Cc toolchain + """ + toolchain = cc_toolchain if cc_toolchain else find_cpp_toolchain(ctx) + feature_configuration = cc_common.configure_features( + cc_toolchain = toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + + return cc_common.is_enabled( + feature_configuration = feature_configuration, + feature_name = "targets_windows", + ) + +def create_linking_info(ctx, user_link_flags, files): + """ Creates CcLinkingInfo for the passed user link options and libraries. + Args: + ctx - rule context + user_link_flags - (list of strings) link optins, provided by user + files - (LibrariesToLink) provider with the library files + """ + cc_toolchain = find_cpp_toolchain(ctx) + for_windows = targets_windows(ctx, cc_toolchain) + + _perform_error_checks( + False, + files.shared_libraries, + files.interface_libraries, + for_windows, + ) + + artifacts = _build_libraries_to_link_and_runtime_artifact( + ctx, + files, + cc_toolchain, + for_windows, + ) + + link_params = _build_cc_link_params(ctx, user_link_flags, **artifacts) + + return CcLinkingInfo(**link_params) + +def getToolsInfo(ctx): + """ Takes information about tools paths from cc_toolchain, returns CxxToolsInfo + Args: + ctx - rule context + """ + cc_toolchain = find_cpp_toolchain(ctx) + feature_configuration = cc_common.configure_features( + cc_toolchain = cc_toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + + return CxxToolsInfo( + cc = cc_common.get_tool_for_action( + feature_configuration = feature_configuration, + action_name = C_COMPILE_ACTION_NAME, + ), + cxx = cc_common.get_tool_for_action( + feature_configuration = feature_configuration, + action_name = CPP_COMPILE_ACTION_NAME, + ), + cxx_linker_static = cc_common.get_tool_for_action( + feature_configuration = feature_configuration, + action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, + ), + cxx_linker_executable = cc_common.get_tool_for_action( + feature_configuration = feature_configuration, + action_name = CPP_LINK_EXECUTABLE_ACTION_NAME, + ), + ) + +def getFlagsInfo(ctx): + """ Takes information about flags from cc_toolchain, returns CxxFlagsInfo + Args: + ctx - rule context + """ + cc_toolchain = find_cpp_toolchain(ctx) + feature_configuration = cc_common.configure_features( + cc_toolchain = cc_toolchain, + requested_features = ctx.features, + unsupported_features = ctx.disabled_features, + ) + copts = ctx.attr.copts if hasattr(ctx.attr, "copts") else depset() + + return CxxFlagsInfo( + cc = cc_common.get_memory_inefficient_command_line( + feature_configuration = feature_configuration, + action_name = C_COMPILE_ACTION_NAME, + variables = cc_common.create_compile_variables( + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + user_compile_flags = copts, + ), + ), + cxx = cc_common.get_memory_inefficient_command_line( + feature_configuration = feature_configuration, + action_name = CPP_COMPILE_ACTION_NAME, + variables = cc_common.create_compile_variables( + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + user_compile_flags = copts, + add_legacy_cxx_options = True, + ), + ), + cxx_linker_shared = cc_common.get_memory_inefficient_command_line( + feature_configuration = feature_configuration, + action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME, + variables = cc_common.create_link_variables( + cc_toolchain = cc_toolchain, + feature_configuration = feature_configuration, + is_using_linker = True, + is_linking_dynamic_library = True, + ), + ), + cxx_linker_static = cc_common.get_memory_inefficient_command_line( + feature_configuration = feature_configuration, + action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME, + variables = cc_common.create_link_variables( + cc_toolchain = cc_toolchain, + feature_configuration = feature_configuration, + is_using_linker = False, + is_linking_dynamic_library = False, + ), + ), + cxx_linker_executable = cc_common.get_memory_inefficient_command_line( + feature_configuration = feature_configuration, + action_name = CPP_LINK_EXECUTABLE_ACTION_NAME, + variables = cc_common.create_link_variables( + cc_toolchain = cc_toolchain, + feature_configuration = feature_configuration, + is_using_linker = True, + is_linking_dynamic_library = False, + ), + ), + assemble = cc_common.get_memory_inefficient_command_line( + feature_configuration = feature_configuration, + action_name = ASSEMBLE_ACTION_NAME, + variables = cc_common.create_compile_variables( + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + user_compile_flags = copts, + ), + ), + ) + +def absolutize_path_in_str(ctx, text, root_str): + """ Replaces relative paths in [the middle of] 'text', prepending them with 'root_str'. + If there is nothing to replace, returns the 'text'. + + We only will replace relative paths starting with either 'external/' or '/', + because we only want to point with absolute paths to external repositories or inside our + current workspace. (And also to limit the possibility of error with such not exact replacing.) + + Args: + ctx - rule context (to determine the top package name) + text - the text to do replacement in + root_str - the text to prepend to the found relative path + """ + package = ctx.label.package + if package.find("/") > 0: + (package, separator, tail) = package.partition("/") + + new_text = _prefix(text, "external/", root_str) + if new_text == text: + new_text = _prefix(text, package + "/", root_str) + + return new_text + +def _prefix(text, from_str, prefix): + (before, middle, after) = text.partition(from_str) + if not middle or before.endswith("/"): + return text + return before + prefix + middle + after diff --git a/tools/build_defs/cmake.bzl b/tools/build_defs/cmake.bzl index fcef0b3e..f79c920e 100644 --- a/tools/build_defs/cmake.bzl +++ b/tools/build_defs/cmake.bzl @@ -1,24 +1,102 @@ """ Defines the rule for building external library with CMake """ -load("//tools/build_defs:framework.bzl", "cc_external_rule_impl", "detect_root", - "CC_EXTERNAL_RULE_ATTRIBUTES", "create_attrs") +load( + "//tools/build_defs:framework.bzl", + "CC_EXTERNAL_RULE_ATTRIBUTES", + "cc_external_rule_impl", + "create_attrs", + "detect_root", +) +load("//tools/build_defs:cc_toolchain_util.bzl", "absolutize_path_in_str", "getFlagsInfo", "getToolsInfo") def _cmake_external(ctx): - options = " ".join(ctx.attr.cmake_options) - root = detect_root(ctx.attr.lib_source) - cmake_string = "cmake -DCMAKE_PREFIX_PATH=\"$EXT_BUILD_ROOT\" -DCMAKE_INSTALL_PREFIX=$INSTALLDIR {} $EXT_BUILD_ROOT/{}".format(options, root) + options = " ".join(ctx.attr.cmake_options) + root = detect_root(ctx.attr.lib_source) - attrs = create_attrs(ctx.attr, - configure_name = 'CMake', - configure_script = cmake_string) + tools = getToolsInfo(ctx) + flags = getFlagsInfo(ctx) - return cc_external_rule_impl(ctx, attrs) + cmake_string = " ".join([ + " ".join(_get_toolchain_variables(ctx, tools, flags)), + " cmake", + " ".join(_get_toolchain_options(ctx, tools, flags)), + "-DCMAKE_PREFIX_PATH=\"$EXT_BUILD_ROOT\"", + "-DCMAKE_INSTALL_PREFIX=$INSTALLDIR", + options, + "$EXT_BUILD_ROOT/" + root, + ]) + + attrs = create_attrs( + ctx.attr, + configure_name = "CMake", + configure_script = cmake_string, + ) + + return cc_external_rule_impl(ctx, attrs) + +def _get_toolchain_variables(ctx, tools, flags): + vars = [] + + if tools.cc: + vars += _env_var(ctx, "CC", [tools.cc]) + if tools.cxx: + vars += _env_var(ctx, "CXX", [tools.cxx]) + if flags.cc: + vars += _env_var(ctx, "CFLAGS", flags.cc) + if flags.cc: + vars += _env_var(ctx, "CXXFLAGS", flags.cxx) + if flags.assemble: + vars += _env_var(ctx, "ASMFLAGS", flags.assemble) + return vars + +def _get_toolchain_options(ctx, tools, flags): + options = [] + if tools.cxx_linker_static: + options += _option(ctx, "CMAKE_AR", [tools.cxx_linker_static]) + + # this does not work by some reason + # options += _option(ctx, "CMAKE_CXX_CREATE_STATIC_LIBRARY", [" qc "]) + # options += _option(ctx, "CMAKE_CXX_ARCHIVE_CREATE", [" qc "]) + # options += _option(ctx, "CMAKE_CXX_ARCHIVE_APPEND", [" qc "]) + # options += _option(ctx, "CMAKE_CXX_ARCHIVE_FINISH", [" "]) + + if tools.cxx_linker_executable: + # https://github.com/Kitware/CMake/blob/master/Modules/CMakeCXXInformation.cmake + rule_string = " ".join([ + "{}", + "", + "", + "", + "", + "-o ", + "", + ]).format(absolutize_path_in_str(ctx, tools.cxx_linker_executable, "$EXT_BUILD_ROOT/")) + options += _option(ctx, "CMAKE_CXX_LINK_EXECUTABLE", [rule_string]) + + # commented out for now, because http://cmake.3232098.n2.nabble.com/CMake-incorrectly-passes-linker-flags-to-ar-td7592436.html + # if flags.cxx_linker_static: + # options += _option(ctx, "CMAKE_STATIC_LINKER_FLAGS", flags.cxx_linker_static) + if flags.cxx_linker_shared: + options += _option(ctx, "CMAKE_SHARED_LINKER_FLAGS", flags.cxx_linker_shared) + if flags.cxx_linker_executable: + options += _option(ctx, "CMAKE_EXE_LINKER_FLAGS", flags.cxx_linker_executable) + + return options + +def _env_var(ctx, cmake_option, flags): + return ["{}=\"{}\"".format(cmake_option, _join_flags_list(ctx, flags))] + +def _option(ctx, cmake_option, flags): + return ["-D{}=\"{}\"".format(cmake_option, _join_flags_list(ctx, flags))] + +def _join_flags_list(ctx, flags): + return " ".join([absolutize_path_in_str(ctx, flag, "$EXT_BUILD_ROOT/") for flag in flags]) def _attrs(): - attrs = dict(CC_EXTERNAL_RULE_ATTRIBUTES) - attrs.update({"cmake_options": attr.string_list(mandatory = False, default = [])}) - return attrs + attrs = dict(CC_EXTERNAL_RULE_ATTRIBUTES) + attrs.update({"cmake_options": attr.string_list(mandatory = False, default = [])}) + return attrs """ Rule for building external library with CMake Attributes: @@ -29,5 +107,5 @@ cmake_external = rule( attrs = _attrs(), fragments = ["cpp"], output_to_genfiles = True, - implementation = _cmake_external + implementation = _cmake_external, ) diff --git a/tools/build_defs/framework.bzl b/tools/build_defs/framework.bzl index 519c4742..c428d1e8 100644 --- a/tools/build_defs/framework.bzl +++ b/tools/build_defs/framework.bzl @@ -3,8 +3,12 @@ """ load("@bazel_skylib//lib:collections.bzl", "collections") -load("//tools/build_defs:cc_linking_util.bzl", "create_linking_info", "LibrariesToLinkInfo", - "targets_windows") +load( + "//tools/build_defs:cc_toolchain_util.bzl", + "LibrariesToLinkInfo", + "create_linking_info", + "targets_windows", +) """ Dict with definitions of the context attributes, that customize cc_external_rule_impl function. Many of the attributes have default values. @@ -13,242 +17,245 @@ load("//tools/build_defs:cc_linking_util.bzl", "create_linking_info", "Libraries description dict. See cmake.bzl as an example. """ CC_EXTERNAL_RULE_ATTRIBUTES = { - # Library name. Defines the name of the install directory and the name of the static library, - # if no output files parameters are defined (any of static_libraries, shared_libraries, - # interface_libraries, binaries_names) - # Optional. If not defined, defaults to the target's name. - "lib_name": attr.string(mandatory = False), - # Label with source code to build. Typically a filegroup for the source of remote repository. - # Mandatory. - "lib_source": attr.label(mandatory = True, allow_files = True), - # Optional compilation definitions to be passed to the dependencies of this library. - # They are NOT passed to the compiler, you should duplicate them in the configuration options. - "defines": attr.string_list(mandatory = False, default = []), - # - # Optional additional inputs to be declared as needed for the shell script action. - # Not used by the shell script part in cc_external_rule_impl. - "additional_inputs": attr.label_list(mandatory = False, allow_files = True, default = []), - # Optional additional tools needed for the building. - # Not used by the shell script part in cc_external_rule_impl. - "additional_tools": attr.label_list(mandatory = False, allow_files = True, default = []), - # - # Optional part of the shell script to be added after the make commands - "postfix_script": attr.string(mandatory = False), - # Optinal make commands, defaults to ["make", "make install"] - "make_commands": attr.string_list(mandatory = False, default = ["make", "make install"]), - # - # Optional dependencies to be copied into the directory structure. - # Typically those directly required for the external building of the library/binaries. - # (i.e. those that the external buidl system will be looking for and paths to which are - # provided by the calling rule) - "deps": attr.label_list(mandatory = False, allow_files = True, default = []), - # Optional tools to be copied into the directory structure. - # Similar to deps, those directly required for the external building of the library/binaries. - "tools_deps": attr.label_list(mandatory = False, allow_files = True, default = []), - # - # Optional name of the output subdirectory with the header files, defaults to 'include'. - "out_include_dir": attr.string(mandatory = False, default = "include"), - # Optional name of the output subdirectory with the library files, defaults to 'lib'. - "out_lib_dir": attr.string(mandatory = False, default = "lib"), - # Optional name of the output subdirectory with the binary files, defaults to 'bin'. - "out_bin_dir": attr.string(mandatory = False, default = "bin"), - # - # Optional. if true, link all the object files from the static library, - # even if they are not used. - "alwayslink": attr.bool(mandatory = False, default = False), - # Optional link options to be passed up to the dependencies of this library - "linkopts": attr.string_list(mandatory = False, default = []), - # - # Output files names parameters. If any of them is defined, only these files are passed to - # Bazel providers. - # if no of them is defined, default lib_name.a/lib_name.lib static library is assumed. - # - # Optional names of the resulting static libraries. - "static_libraries": attr.string_list(mandatory = False), - # Optional names of the resulting shared libraries. - "shared_libraries": attr.string_list(mandatory = False), - # Optional names of the resulting interface libraries. - "interface_libraries": attr.string_list(mandatory = False), - # Optional names of the resulting binaries. - "binaries": attr.string_list(mandatory = False), - # - # Optional name of the output subdirectory with pkgconfig files. - "out_pkg_config_dir": attr.string(mandatory = False), - # link to the shell utilities used by the shell script in cc_external_rule_impl. - "_utils": attr.label( - default = Label("//tools/build_defs:utils.sh"), - allow_single_file = True, - executable = True, - cfg = "target" - ), - # we need to declare this attribute to access cc_toolchain - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + # Library name. Defines the name of the install directory and the name of the static library, + # if no output files parameters are defined (any of static_libraries, shared_libraries, + # interface_libraries, binaries_names) + # Optional. If not defined, defaults to the target's name. + "lib_name": attr.string(mandatory = False), + # Label with source code to build. Typically a filegroup for the source of remote repository. + # Mandatory. + "lib_source": attr.label(mandatory = True, allow_files = True), + # Optional compilation definitions to be passed to the dependencies of this library. + # They are NOT passed to the compiler, you should duplicate them in the configuration options. + "defines": attr.string_list(mandatory = False, default = []), + # + # Optional additional inputs to be declared as needed for the shell script action. + # Not used by the shell script part in cc_external_rule_impl. + "additional_inputs": attr.label_list(mandatory = False, allow_files = True, default = []), + # Optional additional tools needed for the building. + # Not used by the shell script part in cc_external_rule_impl. + "additional_tools": attr.label_list(mandatory = False, allow_files = True, default = []), + # + # Optional part of the shell script to be added after the make commands + "postfix_script": attr.string(mandatory = False), + # Optinal make commands, defaults to ["make", "make install"] + "make_commands": attr.string_list(mandatory = False, default = ["make", "make install"]), + # + # Optional dependencies to be copied into the directory structure. + # Typically those directly required for the external building of the library/binaries. + # (i.e. those that the external buidl system will be looking for and paths to which are + # provided by the calling rule) + "deps": attr.label_list(mandatory = False, allow_files = True, default = []), + # Optional tools to be copied into the directory structure. + # Similar to deps, those directly required for the external building of the library/binaries. + "tools_deps": attr.label_list(mandatory = False, allow_files = True, default = []), + # + # Optional name of the output subdirectory with the header files, defaults to 'include'. + "out_include_dir": attr.string(mandatory = False, default = "include"), + # Optional name of the output subdirectory with the library files, defaults to 'lib'. + "out_lib_dir": attr.string(mandatory = False, default = "lib"), + # Optional name of the output subdirectory with the binary files, defaults to 'bin'. + "out_bin_dir": attr.string(mandatory = False, default = "bin"), + # + # Optional. if true, link all the object files from the static library, + # even if they are not used. + "alwayslink": attr.bool(mandatory = False, default = False), + # Optional link options to be passed up to the dependencies of this library + "linkopts": attr.string_list(mandatory = False, default = []), + # + # Output files names parameters. If any of them is defined, only these files are passed to + # Bazel providers. + # if no of them is defined, default lib_name.a/lib_name.lib static library is assumed. + # + # Optional names of the resulting static libraries. + "static_libraries": attr.string_list(mandatory = False), + # Optional names of the resulting shared libraries. + "shared_libraries": attr.string_list(mandatory = False), + # Optional names of the resulting interface libraries. + "interface_libraries": attr.string_list(mandatory = False), + # Optional names of the resulting binaries. + "binaries": attr.string_list(mandatory = False), + # + # Optional name of the output subdirectory with pkgconfig files. + "out_pkg_config_dir": attr.string(mandatory = False), + # link to the shell utilities used by the shell script in cc_external_rule_impl. + "_utils": attr.label( + default = Label("//tools/build_defs:utils.sh"), + allow_single_file = True, + executable = True, + cfg = "target", + ), + # we need to declare this attribute to access cc_toolchain + "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), } def create_attrs(attr_struct, configure_name, configure_script, **kwargs): - """ Function for adding/modifying context attributes struct (originally from ctx.attr), - provided by user, to be passed to the cc_external_rule_impl function as a struct. + """ Function for adding/modifying context attributes struct (originally from ctx.attr), + provided by user, to be passed to the cc_external_rule_impl function as a struct. - Copies a struct 'attr_struct' values (with attributes from CC_EXTERNAL_RULE_ATTRIBUTES) - to the resulting struct, adding or replacing attributes passed in 'configure_name', - 'configure_script', and '**kwargs' parameters. - """ - dict = {} - for key in CC_EXTERNAL_RULE_ATTRIBUTES: - if not key.startswith("_") and hasattr(attr_struct, key): - dict[key] = getattr(attr_struct, key) + Copies a struct 'attr_struct' values (with attributes from CC_EXTERNAL_RULE_ATTRIBUTES) + to the resulting struct, adding or replacing attributes passed in 'configure_name', + 'configure_script', and '**kwargs' parameters. + """ + dict = {} + for key in CC_EXTERNAL_RULE_ATTRIBUTES: + if not key.startswith("_") and hasattr(attr_struct, key): + dict[key] = getattr(attr_struct, key) - dict["configure_name"] = configure_name - dict["configure_script"] = configure_script + dict["configure_name"] = configure_name + dict["configure_script"] = configure_script - for arg in kwargs: - dict[arg] = kwargs[arg] - return struct(**dict) + for arg in kwargs: + dict[arg] = kwargs[arg] + return struct(**dict) def cc_external_rule_impl(ctx, attrs): - """ Framework function for performing external C/C++ building. + """ Framework function for performing external C/C++ building. - To be used to build external libraries or/and binaries with CMake, configure/make, autotools etc., - and use results in Bazel. - It is possible to use it to build a group of external libraries, that depend on each other or on - Bazel library, and pass nessesary tools. + To be used to build external libraries or/and binaries with CMake, configure/make, autotools etc., + and use results in Bazel. + It is possible to use it to build a group of external libraries, that depend on each other or on + Bazel library, and pass nessesary tools. - Accepts the actual commands for build configuration/execution in attrs. + Accepts the actual commands for build configuration/execution in attrs. - Creates and runs a shell script, which: + Creates and runs a shell script, which: - 1) prepares directory structure with sources, dependencies, and tools symlinked into subdirectories - of the execroot directory. Adds tools into PATH. - 2) defines the correct absolute paths in tools with the script paths, see 7 - 3) defines the following environment variables: - EXT_BUILD_ROOT: execroot directory - EXT_BUILD_DEPS: subdirectory of execroot, which contains the following subdirectories: - include - here the include directories are symlinked - lib - here the library files are symlinked - lib/pkgconfig - here the pkgconfig files are symlinked - bin - here the tools are copied - INSTALLDIR: subdirectory of the execroot (named by the lib_name), where the library/binary - will be installed + 1) prepares directory structure with sources, dependencies, and tools symlinked into subdirectories + of the execroot directory. Adds tools into PATH. + 2) defines the correct absolute paths in tools with the script paths, see 7 + 3) defines the following environment variables: + EXT_BUILD_ROOT: execroot directory + EXT_BUILD_DEPS: subdirectory of execroot, which contains the following subdirectories: + include - here the include directories are symlinked + lib - here the library files are symlinked + lib/pkgconfig - here the pkgconfig files are symlinked + bin - here the tools are copied + INSTALLDIR: subdirectory of the execroot (named by the lib_name), where the library/binary + will be installed - These variables should be used by the calling rule to refer to the created directory structure. - 4) calls 'attrs.configure_script' - 5) calls 'attrs.make_commands' - 6) calls 'attrs.postfix_script' - 7) replaces absolute paths in possibly created scripts with a placeholder value + These variables should be used by the calling rule to refer to the created directory structure. + 4) calls 'attrs.configure_script' + 5) calls 'attrs.make_commands' + 6) calls 'attrs.postfix_script' + 7) replaces absolute paths in possibly created scripts with a placeholder value - Please see cmake.bzl for example usage. + Please see cmake.bzl for example usage. - Args: - ctx: calling rule context - attrs: struct with fields from CC_EXTERNAL_RULE_ATTRIBUTES (see descriptions there), and - two mandatory fields: - configure_name: name of the configuration tool, to be used in action mnemonic - configure_script: actual configuration script - All other fields are ignored. - """ - lib_name = _value(attrs.lib_name, ctx.attr.name) + Args: + ctx: calling rule context + attrs: struct with fields from CC_EXTERNAL_RULE_ATTRIBUTES (see descriptions there), and + two mandatory fields: + configure_name: name of the configuration tool, to be used in action mnemonic + configure_script: actual configuration script + All other fields are ignored. + """ + lib_name = _value(attrs.lib_name, ctx.attr.name) - inputs = _define_inputs(attrs) - outputs = _define_outputs(ctx, attrs, lib_name) - out_cc_info = _define_out_cc_info(ctx, attrs, inputs, outputs) + inputs = _define_inputs(attrs) + outputs = _define_outputs(ctx, attrs, lib_name) + out_cc_info = _define_out_cc_info(ctx, attrs, inputs, outputs) - shell_utils = ctx.attr._utils.files.to_list()[0].path + shell_utils = ctx.attr._utils.files.to_list()[0].path - script_lines = [ - "set -e", - "EXT_BUILD_ROOT=$(pwd)", - "source " + shell_utils, - "echo \"Building external library '{}'\"".format(lib_name), - "TMPDIR=$(mktemp -d)", - "trap \"{ rm -rf $TMPDIR; }\" EXIT", - "EXT_BUILD_DEPS=$(mktemp -d --tmpdir=$EXT_BUILD_ROOT)", - "\n".join(_copy_deps_and_tools(inputs)), - "define_absolute_paths $EXT_BUILD_ROOT/bin $EXT_BUILD_ROOT/bin", - "INSTALLDIR=$EXT_BUILD_ROOT/" + outputs.installdir.path, - "mkdir -p $INSTALLDIR", - "echo_vars INSTALLDIR EXT_BUILD_DEPS EXT_BUILD_ROOT PATH", - "pushd $TMPDIR", - attrs.configure_script, - "\n".join(attrs.make_commands), - _value(attrs.postfix_script, ""), - "replace_absolute_paths $INSTALLDIR $INSTALLDIR", - "popd", - ] + script_lines = [ + "set -e", + "export EXT_BUILD_ROOT=$(pwd)", + "source " + shell_utils, + "echo \"Building external library '{}'\"".format(lib_name), + "TMPDIR=$(mktemp -d)", + "trap \"{ rm -rf $TMPDIR; }\" EXIT", + "export EXT_BUILD_DEPS=$(mktemp -d --tmpdir=$EXT_BUILD_ROOT)", + "\n".join(_copy_deps_and_tools(inputs)), + "define_absolute_paths $EXT_BUILD_ROOT/bin $EXT_BUILD_ROOT/bin", + "export INSTALLDIR=$EXT_BUILD_ROOT/" + outputs.installdir.path, + "mkdir -p $INSTALLDIR", + "echo_vars INSTALLDIR EXT_BUILD_DEPS EXT_BUILD_ROOT PATH", + "pushd $TMPDIR", + attrs.configure_script, + "\n".join(attrs.make_commands), + _value(attrs.postfix_script, ""), + "replace_absolute_paths $INSTALLDIR $INSTALLDIR", + "popd", + ] - script_text = '\n'.join(script_lines) + script_text = "\n".join(script_lines) - ctx.actions.run_shell( - mnemonic="Cc" + attrs.configure_name.capitalize() + "MakeRule", - inputs = inputs.declared_inputs, - outputs = outputs.declared_outputs, - tools = ctx.attr._utils.files, - use_default_shell_env=True, - command = script_text, - execution_requirements = {"block-network": ""} - ) + ctx.actions.run_shell( + mnemonic = "Cc" + attrs.configure_name.capitalize() + "MakeRule", + inputs = inputs.declared_inputs, + outputs = outputs.declared_outputs, + tools = ctx.attr._utils.files, + use_default_shell_env = True, + command = script_text, + execution_requirements = {"block-network": ""}, + ) - return [DefaultInfo(files = depset(direct = outputs.declared_outputs)), - OutputGroupInfo(gen_dir = depset([outputs.installdir]), - bin_dir = depset([outputs.out_bin_dir]), - out_binary_files = depset(outputs.out_binary_files), - pkg_config_dir = outputs.out_pkg_dir or []), - cc_common.create_cc_skylark_info(ctx=ctx), - out_cc_info.compilation_info, - out_cc_info.linking_info, -] + return [ + DefaultInfo(files = depset(direct = outputs.declared_outputs)), + OutputGroupInfo( + gen_dir = depset([outputs.installdir]), + bin_dir = depset([outputs.out_bin_dir]), + out_binary_files = depset(outputs.out_binary_files), + pkg_config_dir = outputs.out_pkg_dir or [], + ), + cc_common.create_cc_skylark_info(ctx = ctx), + out_cc_info.compilation_info, + out_cc_info.linking_info, + ] def _value(value, default_value): - if (value): - return value - return default_value + if (value): + return value + return default_value def _depset(item): - if item == None: - return depset() - return depset([item]) + if item == None: + return depset() + return depset([item]) def _list(item): - if item: - return [item] - return [] + if item: + return [item] + return [] def _copy_deps_and_tools(files): - list = [] - list += _symlink_to_dir("lib", files.libs, False) - list += _symlink_to_dir("include", files.headers, True) - list += _symlink_to_dir("lib/pkgconfig", files.pkg_configs, False) - list += _symlink_to_dir("bin", files.tools_files, False) + list = [] + list += _symlink_to_dir("lib", files.libs, False) + list += _symlink_to_dir("include", files.headers, True) + list += _symlink_to_dir("lib/pkgconfig", files.pkg_configs, False) + list += _symlink_to_dir("bin", files.tools_files, False) - list += ["if [ -d $EXT_BUILD_DEPS/bin ]; then"] - list += [" tools=$(find $EXT_BUILD_DEPS/bin -type d,l -maxdepth 1)"] - list += [" for tool in $tools; do export PATH=$PATH:$tool; done"] - list += ["fi"] - list += ["path $EXT_BUILD_DEPS/bin"] - list += ["export PKG_CONFIG_PATH=$EXT_BUILD_ROOT/lib/pkgconfig"] + list += ["if [ -d $EXT_BUILD_DEPS/bin ]; then"] + list += [" tools=$(find $EXT_BUILD_DEPS/bin -type d,l -maxdepth 1)"] + list += [" for tool in $tools; do export PATH=$PATH:$tool; done"] + list += ["fi"] + list += ["path $EXT_BUILD_DEPS/bin"] + list += ["export PKG_CONFIG_PATH=$EXT_BUILD_ROOT/lib/pkgconfig"] - return list + return list def _symlink_to_dir(dir_name, files_list, link_children): - if len(files_list) == 0: - return [] - list = ["mkdir -p $EXT_BUILD_DEPS/" + dir_name] + if len(files_list) == 0: + return [] + list = ["mkdir -p $EXT_BUILD_DEPS/" + dir_name] - paths_list = [] - for file in files_list: - paths_list += [file if type(file) == "string" else file.path] + paths_list = [] + for file in files_list: + paths_list += [file if type(file) == "string" else file.path] - link_function = "symlink_dir_contents_to_dir" if link_children else "symlink_to_dir" - for path in paths_list: - list += ["{} $EXT_BUILD_ROOT/{} $EXT_BUILD_DEPS/{}".format(link_function, path, dir_name)] + link_function = "symlink_dir_contents_to_dir" if link_children else "symlink_to_dir" + for path in paths_list: + list += ["{} $EXT_BUILD_ROOT/{} $EXT_BUILD_DEPS/{}".format(link_function, path, dir_name)] - return list + return list def _check_file_name(var, name): - if (len(var) == 0): - fail("{} can not be empty string.".format(name.capitalize())) + if (len(var) == 0): + fail("{} can not be empty string.".format(name.capitalize())) - if (not var[0:1].isalpha()): - fail("{} should start with a letter.".format(name.capitalize())) + if (not var[0:1].isalpha()): + fail("{} should start with a letter.".format(name.capitalize())) for index in range(1, len(var) - 1): letter = var[index] if not letter.isalnum() and letter != '_': @@ -265,58 +272,58 @@ _Outputs = provider( out_binary_files = "Binary files, which will be created by the action", libraries = "Library files, which will be created by the action", declared_outputs = "All output files and directories of the action", - ) + ), ) def _define_outputs(ctx, attrs, lib_name): - static_libraries = [] - if (not (hasattr(attrs, "static_libraries") and len(attrs.static_libraries) > 0) and + static_libraries = [] + if (not (hasattr(attrs, "static_libraries") and len(attrs.static_libraries) > 0) and not (hasattr(attrs, "shared_libraries") and len(attrs.shared_libraries) > 0) and not (hasattr(attrs, "interface_libraries") and len(attrs.interface_libraries) > 0) and not (hasattr(attrs, "binaries") and len(attrs.binaries) > 0)): - static_libraries = [lib_name + (".lib" if targets_windows(ctx, None) else ".a")] - else: - static_libraries = attrs.static_libraries + static_libraries = [lib_name + (".lib" if targets_windows(ctx, None) else ".a")] + else: + static_libraries = attrs.static_libraries - _check_file_name(lib_name, "Library name") + _check_file_name(lib_name, "Library name") - out_binary_files = [] - for file in attrs.binaries: - out_binary_files += [_declare_out(ctx, lib_name, attrs.out_bin_dir, file)] + out_binary_files = [] + for file in attrs.binaries: + out_binary_files += [_declare_out(ctx, lib_name, attrs.out_bin_dir, file)] - out_pkg_dir = None - if attrs.out_pkg_config_dir: - out_pkg_dir = ctx.actions.declare_file("/".join([lib_name, attrs.out_pkg_config_dir])) + out_pkg_dir = None + if attrs.out_pkg_config_dir: + out_pkg_dir = ctx.actions.declare_file("/".join([lib_name, attrs.out_pkg_config_dir])) - installdir = ctx.actions.declare_directory(lib_name) - out_include_dir = ctx.actions.declare_directory(lib_name + "/" + attrs.out_include_dir) - out_bin_dir = ctx.actions.declare_directory(lib_name + "/" + attrs.out_bin_dir) - out_lib_dir = ctx.actions.declare_directory(lib_name + "/" + attrs.out_lib_dir) + installdir = ctx.actions.declare_directory(lib_name) + out_include_dir = ctx.actions.declare_directory(lib_name + "/" + attrs.out_include_dir) + out_bin_dir = ctx.actions.declare_directory(lib_name + "/" + attrs.out_bin_dir) + out_lib_dir = ctx.actions.declare_directory(lib_name + "/" + attrs.out_lib_dir) - libraries = LibrariesToLinkInfo( - static_libraries = _declare_out(ctx, lib_name, out_lib_dir, static_libraries), - shared_libraries = _declare_out(ctx, lib_name, out_lib_dir, attrs.shared_libraries), - interface_libraries = _declare_out(ctx, lib_name, out_lib_dir, attrs.interface_libraries), - ) - declared_outputs = [installdir, out_include_dir, out_bin_dir, out_lib_dir] + out_binary_files - declared_outputs += _list(out_pkg_dir) + libraries.static_libraries - declared_outputs += libraries.shared_libraries + libraries.interface_libraries + libraries = LibrariesToLinkInfo( + static_libraries = _declare_out(ctx, lib_name, out_lib_dir, static_libraries), + shared_libraries = _declare_out(ctx, lib_name, out_lib_dir, attrs.shared_libraries), + interface_libraries = _declare_out(ctx, lib_name, out_lib_dir, attrs.interface_libraries), + ) + declared_outputs = [installdir, out_include_dir, out_bin_dir, out_lib_dir] + out_binary_files + declared_outputs += _list(out_pkg_dir) + libraries.static_libraries + declared_outputs += libraries.shared_libraries + libraries.interface_libraries - return _Outputs( - installdir = installdir, - out_include_dir = out_include_dir, - out_bin_dir = out_bin_dir, - out_lib_dir = out_lib_dir, - out_pkg_dir = out_pkg_dir, - out_binary_files = out_binary_files, - libraries = libraries, - declared_outputs = declared_outputs, - ) + return _Outputs( + installdir = installdir, + out_include_dir = out_include_dir, + out_bin_dir = out_bin_dir, + out_lib_dir = out_lib_dir, + out_pkg_dir = out_pkg_dir, + out_binary_files = out_binary_files, + libraries = libraries, + declared_outputs = declared_outputs, + ) def _declare_out(ctx, lib_name, dir, files): - if files and len(files) > 0: - return [ctx.actions.declare_file("/".join([lib_name, dir.basename, file])) for file in files] - return [] + if files and len(files) > 0: + return [ctx.actions.declare_file("/".join([lib_name, dir.basename, file])) for file in files] + return [] _InputFiles = provider( doc = """Provider to keep different kinds of input files, directories, @@ -331,45 +338,45 @@ to be copied into the bin folder, which is added to the PATH""", PKG_CONFIG_PATH is assigned to that folder""", deps_compilation_info = "Merged CcCompilationInfo from deps attribute", deps_linking_info = "Merged CcLinkingInfo from deps attribute", - declared_inputs = "All files and directories that must be declared as action inputs" - ) + declared_inputs = "All files and directories that must be declared as action inputs", + ), ) def _define_inputs(attrs): - pkg_configs = [] - compilation_infos = [] - linking_infos = [] + pkg_configs = [] + compilation_infos = [] + linking_infos = [] - for dep in attrs.deps: - compilation_infos += [dep[CcCompilationInfo]] - linking_infos += [dep[CcLinkingInfo]] + for dep in attrs.deps: + compilation_infos += [dep[CcCompilationInfo]] + linking_infos += [dep[CcLinkingInfo]] - provider = dep[OutputGroupInfo] - if provider and hasattr(provider, "pkg_config_dir"): - # or do we want to be able to produce several files? - pkg_configs += provider.pkg_config_dir.to_list() + provider = dep[OutputGroupInfo] + if provider and hasattr(provider, "pkg_config_dir"): + # or do we want to be able to produce several files? + pkg_configs += provider.pkg_config_dir.to_list() - tools_roots = [] - tools_files = [] - for tool in attrs.tools_deps: - tool_root = detect_root(tool) - tools_roots += [tool_root] - for file_list in tool.files.to_list(): - tools_files += _list(file_list) + tools_roots = [] + tools_files = [] + for tool in attrs.tools_deps: + tool_root = detect_root(tool) + tools_roots += [tool_root] + for file_list in tool.files.to_list(): + tools_files += _list(file_list) - for tool in attrs.additional_tools: - for file_list in tool.files.to_list(): - tools_files += _list(file_list) + for tool in attrs.additional_tools: + for file_list in tool.files.to_list(): + tools_files += _list(file_list) - deps_compilation = cc_common.merge_cc_compilation_infos(cc_compilation_infos = compilation_infos) - deps_linking = cc_common.merge_cc_linking_infos(cc_linking_infos = linking_infos) + deps_compilation = cc_common.merge_cc_compilation_infos(cc_compilation_infos = compilation_infos) + deps_linking = cc_common.merge_cc_linking_infos(cc_linking_infos = linking_infos) - (libs, linkopts) = _collect_libs_and_flags(deps_linking) - headers = [] - for cc_info in compilation_infos: - headers += _get_headers(cc_info) + (libs, linkopts) = _collect_libs_and_flags(deps_linking) + headers = [] + for cc_info in compilation_infos: + headers += _get_headers(cc_info) - return _InputFiles( + return _InputFiles( headers = headers, libs = libs, deps_linkopts = linkopts, @@ -378,70 +385,83 @@ def _define_inputs(attrs): deps_compilation_info = deps_compilation, deps_linking_info = deps_linking, declared_inputs = depset(attrs.lib_source.files) + libs + tools_files + pkg_configs + - attrs.additional_inputs + deps_compilation.headers -) + attrs.additional_inputs + deps_compilation.headers, + ) def _get_headers(compilation_info): - include_dirs = collections.uniq(compilation_info.system_includes.to_list()) - headers = [] - for header in compilation_info.headers: - path = header.path - included = False - for dir in include_dirs: - if path.startswith(dir): - included = True - break - if not included: - headers += [header] - return headers + include_dirs + include_dirs = collections.uniq(compilation_info.system_includes.to_list()) + headers = [] + for header in compilation_info.headers: + path = header.path + included = False + for dir in include_dirs: + if path.startswith(dir): + included = True + break + if not included: + headers += [header] + return headers + include_dirs def _define_out_cc_info(ctx, attrs, inputs, outputs): - compilation_info = CcCompilationInfo(headers = depset([outputs.out_include_dir]), - system_includes = depset([outputs.out_include_dir.path]), - defines = depset(attrs.defines)) - out_compilation_info = cc_common.merge_cc_compilation_infos( - cc_compilation_infos = [inputs.deps_compilation_info, compilation_info]) + compilation_info = CcCompilationInfo( + headers = depset([outputs.out_include_dir]), + system_includes = depset([outputs.out_include_dir.path]), + defines = depset(attrs.defines), + ) + out_compilation_info = cc_common.merge_cc_compilation_infos( + cc_compilation_infos = [inputs.deps_compilation_info, compilation_info], + ) - linkopts = depset(direct = attrs.linkopts, transitive = [depset(inputs.deps_linkopts)]) - linking_info = create_linking_info(ctx, linkopts, outputs.libraries) - out_linking_info = cc_common.merge_cc_linking_infos( - cc_linking_infos = [inputs.deps_linking_info, linking_info]) + linkopts = depset(direct = attrs.linkopts, transitive = [depset(inputs.deps_linkopts)]) + linking_info = create_linking_info(ctx, linkopts, outputs.libraries) + out_linking_info = cc_common.merge_cc_linking_infos( + cc_linking_infos = [inputs.deps_linking_info, linking_info], + ) - return struct( - compilation_info = out_compilation_info, - linking_info = out_linking_info - ) + return struct( + compilation_info = out_compilation_info, + linking_info = out_linking_info, + ) def _collect_libs_and_flags(cc_linking): - libs = [] - linkopts = [] + libs = [] + linkopts = [] - for params in [cc_linking.static_mode_params_for_dynamic_library, - cc_linking.static_mode_params_for_executable, - cc_linking.dynamic_mode_params_for_dynamic_library, - cc_linking.dynamic_mode_params_for_executable]: - libs += [lib.artifact() for lib in params.libraries_to_link.to_list()] - libs += params.dynamic_libraries_for_runtime.to_list() - linkopts = params.linkopts.to_list() + for params in [ + cc_linking.static_mode_params_for_dynamic_library, + cc_linking.static_mode_params_for_executable, + cc_linking.dynamic_mode_params_for_dynamic_library, + cc_linking.dynamic_mode_params_for_executable, + ]: + libs += [lib.artifact() for lib in params.libraries_to_link.to_list()] + libs += params.dynamic_libraries_for_runtime.to_list() + linkopts = params.linkopts.to_list() - return (collections.uniq(libs), collections.uniq(linkopts)) + return (collections.uniq(libs), 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. + """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 (not root or len(root) == 0) and len(sources) > 0: - root = "" - # find topmost directory - for file in sources: - if len(root) == 0 or len(root) > len(file.path): - root = file.path - return root \ No newline at end of file + 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 (not root or len(root) == 0) and len(sources) > 0: + root = "" + + # find topmost directory + for file in sources: + if len(root) == 0 or len(root) > len(file.path): + root = file.path + else: + return root + + (before, sep, after) = root.rpartition("/") + if before and sep and after: + return before + return root