From 9e50f5047d66849643232d0f9634a4d205f1edd9 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Mon, 8 Nov 2021 14:23:30 -0800 Subject: [PATCH 01/10] Update nativeruntime gradle tasks to be run in execution phase Previously, the nativeruntime gradle tasks were run in the configuration phase. Update them to be run in the execution phase using `doLast`. This is more conventional for Gradle tasks and prevents them from be running in certain situations. --- nativeruntime/build.gradle | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/nativeruntime/build.gradle b/nativeruntime/build.gradle index 26c363e10f6..fcd7a2dfe95 100644 --- a/nativeruntime/build.gradle +++ b/nativeruntime/build.gradle @@ -24,29 +24,39 @@ static def arch() { return arch } -task cmakeNativeRuntime(type:Exec) { - workingDir "$buildDir/cpp" - commandLine 'cmake', "$projectDir/cpp/" - doFirst { +task cmakeNativeRuntime { + doLast { mkdir "$buildDir/cpp" + exec { + workingDir "$buildDir/cpp" + commandLine 'cmake', "-B", ".", "-S","$projectDir/cpp/" + } } } -task makeNativeRuntime(type:Exec) { +task makeNativeRuntime { dependsOn cmakeNativeRuntime - workingDir "$buildDir/cpp" - commandLine 'make' + doLast { + exec { + workingDir "$buildDir/cpp" + commandLine 'make' + } + } } -task copyNativeRuntime(type: Copy) { +task copyNativeRuntime { dependsOn makeNativeRuntime - from ("$buildDir/cpp") { - include '*libnativeruntime.*' - } - rename { String fileName -> - fileName.replace("libnativeruntime", "librobolectric-nativeruntime") + doLast { + copy { + from ("$buildDir/cpp") { + include '*libnativeruntime.*' + } + rename { String fileName -> + fileName.replace("libnativeruntime", "librobolectric-nativeruntime") + } + into project.file("$buildDir/resources/main/native/${osName()}/${arch()}/") + } } - into project.file("$buildDir/resources/main/native/${osName()}/${arch()}/") } jar { From beba8a3176b545d5c1e0e5509d56689ebfd5694e Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Mon, 8 Nov 2021 11:03:13 -0800 Subject: [PATCH 02/10] Add the libicu git submodule Unfortunately, Roboelctric will have to get into the business of performing custom libicu builds. As a reminder, libicu is used by Android's SQLite when doing `ORDER BY ... COLLATE UNICODE` and `ORDER BY ... COLLATE LOCALIZED`. In general, Robolectric wants to link the static versions of libicu in order to avoid requiring host machines to have the identical version of libicu that Robolectric was compiled against. This problem is especially bad on Linux, where libicu libraries contain their version number as the suffix, almost guaranteeing that dynamic linking against libicu will not be portable across different machines. For Linux, the system versions of libicu do not contain static libraries that were compiled with `-fPIC`, which means that those static versions of libicu cannot be linked into a shared library, which is required by the JVM. This means that Robolectric needs to link against a version of libicu that was compiled with `-fPIC`. For Mac, we would like to link against a universal library, mainly because this will allow us to cross-compile libicu for both Mac M1 and Mac Intel on a single machine. This will make the CI process much simpler. Another benefit to having libicu as a submldule is that we can guarantee the same version of libicu across all host platforms, which could improve compression ratios of the libicu data files. --- .gitmodules | 6 ++++++ nativeruntime/external/icu | 1 + 2 files changed, 7 insertions(+) create mode 160000 nativeruntime/external/icu diff --git a/.gitmodules b/.gitmodules index 5a3b37d4979..bbbdc092a92 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,9 @@ path = nativeruntime/external/sqlite url = https://android.googlesource.com/platform/external/sqlite branch = android11-release + +[submodule "nativeruntime/external/icu"] + path = nativeruntime/external/icu + url = https://github.com/unicode-org/icu + branch = release-69-1 + shallow = false diff --git a/nativeruntime/external/icu b/nativeruntime/external/icu new file mode 160000 index 00000000000..0e7b4428866 --- /dev/null +++ b/nativeruntime/external/icu @@ -0,0 +1 @@ +Subproject commit 0e7b4428866f3133b4abba2d932ee3faa708db1d From ec15cd6c783808e3614c276cd5d0be9ff28e89aa Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Mon, 8 Nov 2021 12:20:36 -0800 Subject: [PATCH 03/10] Use the icu submodule for building libicu Add Gradle tasks that execute `runConfigureICU` with the appropriate flags. On Linux, this involves passing `-fPIC` to allow static linking. On Macc, this involves passing `-arch x86_64 -arch arm64` to build universal libraries. Also, update CMakeLists.txt to use the submodule version of ICU instead of the homebrew version. This also involves updating NativeRuntimeLoader to load the universal mac library. --- nativeruntime/build.gradle | 43 +++++++++++- nativeruntime/cpp/CMakeLists.txt | 65 ++++++++----------- .../nativeruntime/NativeRuntimeLoader.java | 7 +- 3 files changed, 75 insertions(+), 40 deletions(-) diff --git a/nativeruntime/build.gradle b/nativeruntime/build.gradle index fcd7a2dfe95..eaad604b661 100644 --- a/nativeruntime/build.gradle +++ b/nativeruntime/build.gradle @@ -34,7 +34,43 @@ task cmakeNativeRuntime { } } +task configureICU { + if (!file("$projectDir/external/icu/icu4c/source").exists()) { + throw new GradleException("ICU submodule not detected. Please run `git submodule update --init`") + } + onlyIf { !file("$projectDir/external/icu/icu4c/source/Makefile").exists() } + doLast { + exec { + def os = osName() + workingDir "$projectDir/external/icu/icu4c/source" + if (os.contains("linux")) { + environment "CFLAGS", "-fPIC" + environment "CXXFLAGS", "-fPIC" + commandLine './runConfigureICU', 'Linux', '--enable-static', '--disable-shared' + } else if (os.contains("mac")) { + environment "CFLAGS", "-arch x86_64 -arch arm64" + environment "CXXFLAGS", "-arch x86_64 -arch arm64" + commandLine './runConfigureICU', 'MacOSX', '--enable-static', '--disable-shared' + } + } + } +} + +task buildICU { + dependsOn configureICU + if (!file("$projectDir/external/icu/icu4c/source").exists()) { + throw new GradleException("ICU submodule not detected. Please run `git submodule update --init`") + } + doLast { + exec { + workingDir "$projectDir/external/icu/icu4c/source" + commandLine 'make', '-j4' + } + } +} + task makeNativeRuntime { + dependsOn buildICU dependsOn cmakeNativeRuntime doLast { exec { @@ -54,7 +90,12 @@ task copyNativeRuntime { rename { String fileName -> fileName.replace("libnativeruntime", "librobolectric-nativeruntime") } - into project.file("$buildDir/resources/main/native/${osName()}/${arch()}/") + def os = osName() + def arch = arch() + if (os.contains("mac")) { + arch = "universal" + } + into project.file("$buildDir/resources/main/native/${os}/${arch}/") } } } diff --git a/nativeruntime/cpp/CMakeLists.txt b/nativeruntime/cpp/CMakeLists.txt index 86f06e71896..70038ae918e 100644 --- a/nativeruntime/cpp/CMakeLists.txt +++ b/nativeruntime/cpp/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 3.10) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64") # Universal libraries for Mac OS + project(nativeruntime) # Some libutils headers require C++17 @@ -7,44 +10,32 @@ set (CMAKE_CXX_STANDARD 17) find_package(JNI REQUIRED) -# On Mac OS, search Homebrew for the icu4c distribution. The system version -# does not include headers and static libraries. -if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin") - execute_process( - COMMAND brew --prefix icu4c - RESULT_VARIABLE BREW_ICU4C - OUTPUT_VARIABLE BREW_ICU4C_PREFIX - OUTPUT_STRIP_TRAILING_WHITESPACE - ) +set(ANDROID_SQLITE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/sqlite") - if (NOT BREW_ICU4C EQUAL 0) - message( FATAL_ERROR "'brew --prefix icu4c' failed. Ensure homebrew is installed and run 'brew install icu4c'.") - endif() - - if (BREW_ICU4C EQUAL 0 AND EXISTS "${BREW_ICU4C_PREFIX}") - message(STATUS "Found icu4c installed by Homebrew at ${BREW_ICU4C_PREFIX}") - list(APPEND CMAKE_PREFIX_PATH ${BREW_ICU4C_PREFIX}) - find_library(BREW_ICUUC_LIBRARY libicuuc.a) - find_library(BREW_ICUI18N_LIBRARY libicui18n.a) - find_library(BREW_ICUDATA_LIBRARY libicudata.a) - include_directories(${BREW_ICU4C_PREFIX}/include) - endif() - - if (NOT BREW_ICUUC_LIBRARY) - message(FATAL_ERROR "libicuuc.a not found. Please run 'brew install icu4c'") - endif() +if(NOT EXISTS "${ANDROID_SQLITE_DIR}/dist/sqlite3.c") + message(FATAL_ERROR "SQLite submodule missing. Please run `git submodule update --init`.") endif() -set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(ICU_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/icu") -# Build flags derived from -# https://cs.android.com/android/platform/superproject/+/android-11.0.0_r1:external/sqlite/dist/Android.bp -set(ANDROID_SQLITE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/sqlite") +if(NOT EXISTS "${ICU_DIR}/icu4c/source/i18n/ucol.cpp") + message(FATAL_ERROR "ICU submodule missing. Please run `git submodule update --init`.") +endif() -if(NOT EXISTS "${ANDROID_SQLITE_DIR}/dist/sqlite3.c") - message(FATAL_ERROR "SQLite submodule missing. Please run `git submodule update --init`.") +if(NOT EXISTS "${ICU_DIR}/icu4c/source/lib/libicui18n.a") + message(FATAL_ERROR "ICU not built. Please run `./gradlew :nativeruntime:buildICU`.") endif() +list(APPEND CMAKE_PREFIX_PATH "${ICU_DIR}/icu4c/source/") +find_library(STATIC_ICUI18N_LIBRARY libicui18n.a) +find_library(STATIC_ICUUC_LIBRARY libicuuc.a) +find_library(STATIC_ICUDATA_LIBRARY libicudata.a) +include_directories(${ICU_DIR}/icu4c/source/i18n) +include_directories(${ICU_DIR}/icu4c/source/common) + +# Build flags derived from +# https://cs.android.com/android/platform/superproject/+/android-11.0.0_r1:external/sqlite/dist/Android.bp + set(SQLITE_COMPILE_OPTIONS -DHAVE_USLEEP=1 -DNDEBUG=1 @@ -84,13 +75,11 @@ add_library(androidsqlite STATIC target_compile_options(androidsqlite PRIVATE ${SQLITE_COMPILE_OPTIONS}) -if (CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin") - target_link_libraries(androidsqlite - ${BREW_ICUUC_LIBRARY} - ${BREW_ICUI18N_LIBRARY} - ${BREW_ICUDATA_LIBRARY} - ) -endif() +target_link_libraries(androidsqlite + ${STATIC_ICUI18N_LIBRARY} + ${STATIC_ICUUC_LIBRARY} + ${STATIC_ICUDATA_LIBRARY} +) include_directories(${JNI_INCLUDE_DIRS}) diff --git a/nativeruntime/src/main/java/org/robolectric/nativeruntime/NativeRuntimeLoader.java b/nativeruntime/src/main/java/org/robolectric/nativeruntime/NativeRuntimeLoader.java index 4ee9a4dabad..a00e1204d56 100644 --- a/nativeruntime/src/main/java/org/robolectric/nativeruntime/NativeRuntimeLoader.java +++ b/nativeruntime/src/main/java/org/robolectric/nativeruntime/NativeRuntimeLoader.java @@ -50,8 +50,13 @@ private static boolean isSupported() { } private static String nativeLibraryPath() { + String os = osName(); + String arch = arch(); + if (os.equals("mac")) { + arch = "universal"; // use the universal library + } return String.format( - "native/%s/%s/%s", osName(), arch(), System.mapLibraryName("robolectric-nativeruntime")); + "native/%s/%s/%s", os, arch, System.mapLibraryName("robolectric-nativeruntime")); } private static String osName() { From e16dbce0d6cf51d31b35fed35145f062168079b2 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Mon, 8 Nov 2021 15:47:04 -0800 Subject: [PATCH 04/10] Print an error if there are any undefined symbols during linking Also, link to libdl and libpthread to avoid undefined symbols. --- nativeruntime/cpp/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nativeruntime/cpp/CMakeLists.txt b/nativeruntime/cpp/CMakeLists.txt index 70038ae918e..33100f8503d 100644 --- a/nativeruntime/cpp/CMakeLists.txt +++ b/nativeruntime/cpp/CMakeLists.txt @@ -121,5 +121,8 @@ if (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux") target_link_libraries(nativeruntime -static-libgcc -static-libstdc++ + -ldl + -lpthread + -Wl,--no-undefined # print an error if there are any undefined symbols ) endif() From 02fd81090aa912135f47930a76a6a4715e26ad55 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Mon, 8 Nov 2021 20:03:18 -0800 Subject: [PATCH 05/10] Use clang to build libnativeruntime --- .github/workflows/tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e58eb7bba2c..fe45c3db308 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -31,6 +31,9 @@ jobs: java-version: 11.0.8 - name: Build + env: + CXX: clang++ + CC: clang run: SKIP_ERRORPRONE=true SKIP_JAVADOC=true ./gradlew clean assemble testClasses --parallel --stacktrace unit-tests: From 7fcc2fdd201f79d42fc3931abaa943d13dbd71fc Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Tue, 9 Nov 2021 07:45:34 -0800 Subject: [PATCH 06/10] Add support for an external ICU root dir The goal of this is to support CI environments where we do not want to rebuild libICU at every step. The CI environment will cache the ICU installation after being built and pass the directory. --- nativeruntime/build.gradle | 18 ++++++++------ nativeruntime/cpp/CMakeLists.txt | 41 ++++++++++++++++++++------------ 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/nativeruntime/build.gradle b/nativeruntime/build.gradle index eaad604b661..d2ead4ea506 100644 --- a/nativeruntime/build.gradle +++ b/nativeruntime/build.gradle @@ -35,13 +35,14 @@ task cmakeNativeRuntime { } task configureICU { + onlyIf { !System.getenv('SKIP_ICU_BUILD') } + if (!file("$projectDir/external/icu/icu4c/source").exists()) { throw new GradleException("ICU submodule not detected. Please run `git submodule update --init`") } - onlyIf { !file("$projectDir/external/icu/icu4c/source/Makefile").exists() } + def os = osName() doLast { exec { - def os = osName() workingDir "$projectDir/external/icu/icu4c/source" if (os.contains("linux")) { environment "CFLAGS", "-fPIC" @@ -51,20 +52,23 @@ task configureICU { environment "CFLAGS", "-arch x86_64 -arch arm64" environment "CXXFLAGS", "-arch x86_64 -arch arm64" commandLine './runConfigureICU', 'MacOSX', '--enable-static', '--disable-shared' + } else { + println("Skipping the nativeruntime build for OS '${System.getProperty("os.name")}'") } } } } task buildICU { + onlyIf { !System.getenv('SKIP_ICU_BUILD') } dependsOn configureICU - if (!file("$projectDir/external/icu/icu4c/source").exists()) { - throw new GradleException("ICU submodule not detected. Please run `git submodule update --init`") - } + def os = osName() doLast { exec { - workingDir "$projectDir/external/icu/icu4c/source" - commandLine 'make', '-j4' + if (os.contains("linux") || os.contains("mac")) { + workingDir "$projectDir/external/icu/icu4c/source" + commandLine 'make', '-j4' + } } } } diff --git a/nativeruntime/cpp/CMakeLists.txt b/nativeruntime/cpp/CMakeLists.txt index 33100f8503d..6ae537bb2b9 100644 --- a/nativeruntime/cpp/CMakeLists.txt +++ b/nativeruntime/cpp/CMakeLists.txt @@ -16,23 +16,34 @@ if(NOT EXISTS "${ANDROID_SQLITE_DIR}/dist/sqlite3.c") message(FATAL_ERROR "SQLite submodule missing. Please run `git submodule update --init`.") endif() -set(ICU_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/icu") - -if(NOT EXISTS "${ICU_DIR}/icu4c/source/i18n/ucol.cpp") - message(FATAL_ERROR "ICU submodule missing. Please run `git submodule update --init`.") -endif() - -if(NOT EXISTS "${ICU_DIR}/icu4c/source/lib/libicui18n.a") - message(FATAL_ERROR "ICU not built. Please run `./gradlew :nativeruntime:buildICU`.") +if(DEFINED ENV{ICU_ROOT_DIR}) + message(NOTICE "Using $ENV{ICU_ROOT_DIR} as the ICU root dir") + list(APPEND CMAKE_PREFIX_PATH "$ENV{ICU_ROOT_DIR}") + find_library(STATIC_ICUI18N_LIBRARY libicui18n.a) + find_library(STATIC_ICUUC_LIBRARY libicuuc.a) + find_library(STATIC_ICUDATA_LIBRARY libicudata.a) + include_directories($ENV{ICU_ROOT_DIR}/include) +else() + set(ICU_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/icu") + + if(NOT EXISTS "${ICU_DIR}/icu4c/source/i18n/ucol.cpp") + message(FATAL_ERROR "ICU submodule missing. Please run `git submodule update --init`.") + endif() + + message(NOTICE "Using ${ICU_DIR} as the ICU root dir") + + if(NOT EXISTS "${ICU_DIR}/icu4c/source/lib/libicui18n.a") + message(FATAL_ERROR "ICU not built. Please run `./gradlew :nativeruntime:buildICU`.") + endif() + + list(APPEND CMAKE_PREFIX_PATH "${ICU_DIR}/icu4c/source/") + find_library(STATIC_ICUI18N_LIBRARY libicui18n.a) + find_library(STATIC_ICUUC_LIBRARY libicuuc.a) + find_library(STATIC_ICUDATA_LIBRARY libicudata.a) + include_directories(${ICU_DIR}/icu4c/source/i18n) + include_directories(${ICU_DIR}/icu4c/source/common) endif() -list(APPEND CMAKE_PREFIX_PATH "${ICU_DIR}/icu4c/source/") -find_library(STATIC_ICUI18N_LIBRARY libicui18n.a) -find_library(STATIC_ICUUC_LIBRARY libicuuc.a) -find_library(STATIC_ICUDATA_LIBRARY libicudata.a) -include_directories(${ICU_DIR}/icu4c/source/i18n) -include_directories(${ICU_DIR}/icu4c/source/common) - # Build flags derived from # https://cs.android.com/android/platform/superproject/+/android-11.0.0_r1:external/sqlite/dist/Android.bp From 25de1e8348a75f9d4ce409f74473c8c6b9e59396 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Tue, 9 Nov 2021 08:09:49 -0800 Subject: [PATCH 07/10] Add caching for libICU build artifacts when running workflows --- .github/workflows/tests.yml | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fe45c3db308..fac8f60ea45 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,6 +7,10 @@ on: pull_request: branches: [ master ] +env: + CXX: clang++ + CC: clang + jobs: build: runs-on: ubuntu-18.04 @@ -20,21 +24,33 @@ jobs: path: | ~/.gradle ~/.m2 - ~/sqlite key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }} restore-keys: | ${{ runner.os }}-gradle- + - name: Set up JDK 11.0.8 uses: actions/setup-java@v1 with: java-version: 11.0.8 + - name: Cache ICU build output + id: cache-icu + uses: actions/cache@v2 + with: + path: ~/icu-bin + key: ${{ runner.os }}-icu-${{ hashFiles('nativeruntime/external/icu/**') }} + + - name: Build ICU + if: steps.cache-icu.outputs.cache-hit != 'true' + run: | + cd nativeruntime/external/icu/icu4c/source + CFLAGS="-fPIC" CXXFLAGS="-fPIC" ./runConfigureICU Linux --enable-static --prefix=$HOME/icu-bin + make -j4 + make install + - name: Build - env: - CXX: clang++ - CC: clang - run: SKIP_ERRORPRONE=true SKIP_JAVADOC=true ./gradlew clean assemble testClasses --parallel --stacktrace + run: ICU_ROOT_DIR=$HOME/icu-bin SKIP_ICU_BUILD=true SKIP_ERRORPRONE=true SKIP_JAVADOC=true ./gradlew clean assemble testClasses --parallel --stacktrace unit-tests: runs-on: ubuntu-18.04 @@ -63,9 +79,16 @@ jobs: with: java-version: 11.0.8 + - name: Cache ICU build output + id: cache-icu + uses: actions/cache@v2 + with: + path: ~/icu-bin + key: ${{ runner.os }}-icu-${{ hashFiles('nativeruntime/external/icu/**') }} + - name: Run unit tests run: | - SKIP_ERRORPRONE=true SKIP_JAVADOC=true ./gradlew test --info --stacktrace --continue \ + ICU_ROOT_DIR=$HOME/icu-bin SKIP_ICU_BUILD=true SKIP_ERRORPRONE=true SKIP_JAVADOC=true ./gradlew test --info --stacktrace --continue \ --parallel \ -Drobolectric.enabledSdks=${{ matrix.api-versions }} \ -Drobolectric.alwaysIncludeVariantMarkersInTestName=true \ From a0d3f1d44cafe930ae04ea665603e753c9935924 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Tue, 9 Nov 2021 11:12:05 -0800 Subject: [PATCH 08/10] Move icu submodule check to Gradle execution phase This allows tasks that do not need the icu submodule to execute without setting it up. --- nativeruntime/build.gradle | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/nativeruntime/build.gradle b/nativeruntime/build.gradle index d2ead4ea506..832404f5e80 100644 --- a/nativeruntime/build.gradle +++ b/nativeruntime/build.gradle @@ -36,12 +36,11 @@ task cmakeNativeRuntime { task configureICU { onlyIf { !System.getenv('SKIP_ICU_BUILD') } - - if (!file("$projectDir/external/icu/icu4c/source").exists()) { - throw new GradleException("ICU submodule not detected. Please run `git submodule update --init`") - } def os = osName() doLast { + if (!file("$projectDir/external/icu/icu4c/source").exists()) { + throw new GradleException("ICU submodule not detected. Please run `git submodule update --init`") + } exec { workingDir "$projectDir/external/icu/icu4c/source" if (os.contains("linux")) { From b36f8aed87c6e8009565c871ff3ff059e00edad7 Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Tue, 9 Nov 2021 11:18:24 -0800 Subject: [PATCH 09/10] Skip the native runtime build during the check_aggregateDocs workflow It is not required to check Javadoc. --- .github/workflows/check_aggregateDocs.yml | 4 ++-- nativeruntime/build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/check_aggregateDocs.yml b/.github/workflows/check_aggregateDocs.yml index a178a47862b..ee23ae704df 100644 --- a/.github/workflows/check_aggregateDocs.yml +++ b/.github/workflows/check_aggregateDocs.yml @@ -17,7 +17,7 @@ jobs: fetch-depth: 0 submodules: recursive - - name: Set up JDK + - name: Set up JDK uses: actions/setup-java@v2 with: distribution: 'zulu' # zulu suports complete JDK list @@ -25,4 +25,4 @@ jobs: cache: 'gradle' - name: Run aggregateDocs - run: ./gradlew clean aggregateDocs + run: SKIP_NATIVERUNTIME_BUILD=true ./gradlew clean aggregateDocs # building the native runtime is not required for checking javadoc diff --git a/nativeruntime/build.gradle b/nativeruntime/build.gradle index 832404f5e80..6180e615376 100644 --- a/nativeruntime/build.gradle +++ b/nativeruntime/build.gradle @@ -105,7 +105,7 @@ task copyNativeRuntime { jar { def os = osName() - if (os.contains("linux") || os.contains("mac")) { + if (!System.getenv('SKIP_NATIVERUNTIME_BUILD') && (os.contains("linux") || os.contains("mac"))) { dependsOn copyNativeRuntime } else { println("Skipping the nativeruntime build for OS '${System.getProperty("os.name")}'") From 08dbd81847e54f79ad3f1265a5b5b8474b010a0f Mon Sep 17 00:00:00 2001 From: Michael Hoisie Date: Tue, 9 Nov 2021 18:13:35 -0500 Subject: [PATCH 10/10] Specify clang and clang++ when building nativeruntime Currently building nativeruntime only works with clang. Using gcc will result in obscure linker errors related to missing symbols in libstdc++. While it would be nice to support both, clang is sufficient for now, and it is fairly easy to obtain on all platforms. Also add some more error checks for various edge cases. --- .github/workflows/tests.yml | 1 - nativeruntime/build.gradle | 8 ++++++-- nativeruntime/cpp/CMakeLists.txt | 19 ++++++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index fac8f60ea45..01ce505a5cf 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -28,7 +28,6 @@ jobs: restore-keys: | ${{ runner.os }}-gradle- - - name: Set up JDK 11.0.8 uses: actions/setup-java@v1 with: diff --git a/nativeruntime/build.gradle b/nativeruntime/build.gradle index 6180e615376..8d1405d0041 100644 --- a/nativeruntime/build.gradle +++ b/nativeruntime/build.gradle @@ -28,6 +28,10 @@ task cmakeNativeRuntime { doLast { mkdir "$buildDir/cpp" exec { + // Building the nativeruntime does not work with GCC due to libstddc++ linker errors. + // TODO: figure out which linker args are needed to build with GCC. + environment "CC", "clang" + environment "CXX", "clang++" workingDir "$buildDir/cpp" commandLine 'cmake', "-B", ".", "-S","$projectDir/cpp/" } @@ -36,8 +40,8 @@ task cmakeNativeRuntime { task configureICU { onlyIf { !System.getenv('SKIP_ICU_BUILD') } - def os = osName() doLast { + def os = osName() if (!file("$projectDir/external/icu/icu4c/source").exists()) { throw new GradleException("ICU submodule not detected. Please run `git submodule update --init`") } @@ -61,9 +65,9 @@ task configureICU { task buildICU { onlyIf { !System.getenv('SKIP_ICU_BUILD') } dependsOn configureICU - def os = osName() doLast { exec { + def os = osName() if (os.contains("linux") || os.contains("mac")) { workingDir "$projectDir/external/icu/icu4c/source" commandLine 'make', '-j4' diff --git a/nativeruntime/cpp/CMakeLists.txt b/nativeruntime/cpp/CMakeLists.txt index 6ae537bb2b9..69e4a0d8318 100644 --- a/nativeruntime/cpp/CMakeLists.txt +++ b/nativeruntime/cpp/CMakeLists.txt @@ -17,6 +17,11 @@ if(NOT EXISTS "${ANDROID_SQLITE_DIR}/dist/sqlite3.c") endif() if(DEFINED ENV{ICU_ROOT_DIR}) + + if(NOT EXISTS "$ENV{ICU_ROOT_DIR}/lib/libicui18n.a") + message(FATAL_ERROR "ICU_ROOT_DIR does not contain 'lib/libicui18n.a'") + endif() + message(NOTICE "Using $ENV{ICU_ROOT_DIR} as the ICU root dir") list(APPEND CMAKE_PREFIX_PATH "$ENV{ICU_ROOT_DIR}") find_library(STATIC_ICUI18N_LIBRARY libicui18n.a) @@ -24,24 +29,24 @@ if(DEFINED ENV{ICU_ROOT_DIR}) find_library(STATIC_ICUDATA_LIBRARY libicudata.a) include_directories($ENV{ICU_ROOT_DIR}/include) else() - set(ICU_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/icu") + set(ICU_SUBMODULE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../external/icu") - if(NOT EXISTS "${ICU_DIR}/icu4c/source/i18n/ucol.cpp") + if(NOT EXISTS "${ICU_SUBMODULE_DIR}/icu4c/source/i18n/ucol.cpp") message(FATAL_ERROR "ICU submodule missing. Please run `git submodule update --init`.") endif() - message(NOTICE "Using ${ICU_DIR} as the ICU root dir") + message(NOTICE "Using ${ICU_SUBMODULE_DIR} as the ICU root dir") - if(NOT EXISTS "${ICU_DIR}/icu4c/source/lib/libicui18n.a") + if(NOT EXISTS "${ICU_SUBMODULE_DIR}/icu4c/source/lib/libicui18n.a") message(FATAL_ERROR "ICU not built. Please run `./gradlew :nativeruntime:buildICU`.") endif() - list(APPEND CMAKE_PREFIX_PATH "${ICU_DIR}/icu4c/source/") + list(APPEND CMAKE_PREFIX_PATH "${ICU_SUBMODULE_DIR}/icu4c/source/") find_library(STATIC_ICUI18N_LIBRARY libicui18n.a) find_library(STATIC_ICUUC_LIBRARY libicuuc.a) find_library(STATIC_ICUDATA_LIBRARY libicudata.a) - include_directories(${ICU_DIR}/icu4c/source/i18n) - include_directories(${ICU_DIR}/icu4c/source/common) + include_directories(${ICU_SUBMODULE_DIR}/icu4c/source/i18n) + include_directories(${ICU_SUBMODULE_DIR}/icu4c/source/common) endif() # Build flags derived from