Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CI: build in Docker with MUSL libc for static library #736

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,17 @@ jobs:
build-debug:
name: Build and test in Debug mode
#currently cannot run on Linux & Debug due to a bug in YAML parser: issue #218
runs-on: macOS-latest
runs-on: ubuntu-18.04
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

switching to ubuntu for we can use gcc-8 (c++17) there

steps:
- uses: actions/checkout@v1

- name: Install dependencies (Debug)
env:
CC: gcc-8
CXX: g++-8
run: |
sudo apt-get update
sudo apt-get -y install gcc-8 g++-8
echo "built type: ${CMAKE_BUILD_TYPE}"
mkdir -p build/scripts
cd build/scripts
Expand Down Expand Up @@ -200,7 +205,7 @@ jobs:

- name: Tests
run: |
sudo docker run -it htm-arm64-docker
sudo docker run -it htm-arm64-docker /bin/sh
uname -a && echo "\nHello from ARM64 htm.core build!\n"
python setup.py test
exit
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ set($ENV{HTM_CPP} ${REPOSITORY_DIR})
option(FORCE_CPP11 "Force compiler to use C++11 standard." OFF)
option(FORCE_BOOST "Force compiler to install and use Boost." OFF)
set(BINDING_BUILD "none" CACHE STRING "Specify the Binding to build 'Python2','Python3' or 'none', default 'none'." )
set(NTA_LIBC_MUSL OFF CACHE BOOL "Are we using MUSL stdlibc++, or GLIBC?")
breznak marked this conversation as resolved.
Show resolved Hide resolved

# Note: by setting the CXX environment variable, a non-default c++ compiler can be specified.

if(MSVC AND BINDING_BUILD STREQUAL "Python2")
Expand Down
32 changes: 4 additions & 28 deletions CommonCompilerConfig.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
##############################################################

include(CheckCXXCompilerFlag)

#set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_INLINES_HIDDEN ON)

# Identify platform name.
if(NOT PLATFORM)
Expand Down Expand Up @@ -227,6 +228,7 @@ else()
-DHAVE_CONFIG_H
-DBOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
-DBOOST_NO_WREGEX
-DNTA_LIBC_MUSL=${NTA_LIBC_MUSL}
)

if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "Release")
Expand All @@ -253,40 +255,16 @@ else()
# endif()


#
# Determine stdlib settings
#
set(stdlib_cxx)
set(stdlib_common)

if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(stdlib_cxx ${stdlib_cxx} -stdlib=libc++)
endif()

# TODO: investigate if we should use static or shared stdlib and gcc lib.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-static never worked properly with gcc, so we'll use musl for the binary releases.

if (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
set(stdlib_common ${stdlib_common} -static-libgcc)
set(stdlib_cxx ${stdlib_cxx} -static-libstdc++)
endif()



#
# compiler specific settings and warnings here
#
set(internal_compiler_warning_flags)
set(cxx_flags_unoptimized)
set(linker_flags_unoptimized)

# Hide all symbols in DLLs except the ones with explicit visibility;
# see https://gcc.gnu.org/wiki/Visibility
set(cxx_flags_unoptimized ${cxx_flags_unoptimized} -fvisibility-inlines-hidden )


# LLVM Clang / Gnu GCC
set(cxx_flags_unoptimized ${cxx_flags_unoptimized} ${stdlib_cxx})

set(cxx_flags_unoptimized ${cxx_flags_unoptimized} ${stdlib_common} -fdiagnostics-show-option)
set(cxx_flags_unoptimized ${cxx_flags_unoptimized} -fdiagnostics-show-option)
set (internal_compiler_warning_flags ${internal_compiler_warning_flags} -Werror -Wextra -Wreturn-type -Wunused -Wno-unused-variable -Wno-unused-parameter -Wno-missing-field-initializers)

CHECK_CXX_COMPILER_FLAG(-m${BITNESS} compiler_supports_machine_option)
Expand All @@ -308,8 +286,6 @@ else()
endif()
endif()

set(shared_linker_flags_unoptimized ${shared_linker_flags_unoptimized} ${stdlib_common} ${stdlib_cxx})

# Don't allow undefined symbols when linking executables
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
set(linker_flags_unoptimized ${linker_flags_unoptimized} -Wl,--no-undefined)
Expand Down
14 changes: 5 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
## To run a build using this file locally, do:
# docker run --privileged --rm -it multiarch/qemu-user-static:register
# docker build -t htm-arm64-docker --build-arg arch=arm64 .
# docker run -it htm-arm64-docker
# docker run -it htm-arm64-docker /bin/sh

#target compile arch
ARG arch=arm64
Expand Down Expand Up @@ -38,12 +38,8 @@ ADD . /usr/local/src/htm.core
WORKDIR /usr/local/src/htm.core

# Setup py env
#! RUN python3 -m venv pyenv && . pyenv/bin/activate && python --version

RUN ln -s /usr/bin/python3 /usr/local/bin/python && python --version

RUN python -m pip install --upgrade setuptools pip wheel

# Install
RUN python -m pip uninstall -y htm.core
RUN python -m pip install \
Expand All @@ -54,16 +50,16 @@ RUN python -m pip install \
# --build /usr/local/src/htm.core/pip-build \
# --no-clean \
-r requirements.txt
RUN mkdir -p build/scripts && \
RUN rm -rf build/ && \
mkdir -p build/scripts && \
cd build/scripts && \
cmake ../.. -DCMAKE_BUILD_TYPE=Release -DBINDING_BUILD=Python3 && \
cmake ../.. -DCMAKE_BUILD_TYPE=Release -DBINDING_BUILD=Python3 -DNTA_LIBC_MUSL=1 && \
make -j4 && make install

RUN python setup.py install --force

# Test
#RUN python setup.py test #Note, if you get weird import errors here,
# do `git clean -xdf` in your host system, and rerun the docker
#RUN python setup.py test

## Stage 2: create release packages (for PyPI, GH Releases)
RUN python setup.py bdist_wheel
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ specifically.
docker build --build-arg arch=arm64 .
```

> Note: When building on platforms that use MUSL stdlibc++ instead of GLIBC, such as Alpine linux in our Docker container,
you need to pass `-DNTA_LIBC_MUSL=1` to the `cmake` command. In the `Dockerfile` this is done automatically.


### Automated Builds, CI

We use Github `Actions` to build and run multiplatform (OSX, Windows, Linux, ARM64) tests and releases.
Expand Down
6 changes: 3 additions & 3 deletions external/gtest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
if(EXISTS "${REPOSITORY_DIR}/build/ThirdParty/share/googletest.tar.gz")
set(URL "${REPOSITORY_DIR}/build/ThirdParty/share/googletest.tar.gz")
else()
set(URL https://github.com/abseil/googletest/archive/release-1.8.1.tar.gz)
set(URL https://github.com/abseil/googletest/archive/release-1.10.0.tar.gz)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bump gtest

endif()

#
Expand All @@ -54,12 +54,12 @@ set(BUILD_GMOCK OFF CACHE BOOL "prevents building gmock" FORCE)
add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR})

if(MSVC)
set(gtest_LIBRARIES ${googletest_BINARY_DIR}/googletest/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/${CMAKE_STATIC_LIBRARY_PREFIX}gtest$<$<CONFIG:Debug>:d>${CMAKE_STATIC_LIBRARY_SUFFIX})
set(gtest_LIBRARIES ${EP_BASE}/lib/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/${CMAKE_STATIC_LIBRARY_PREFIX}gtest$<$<CONFIG:Debug>:d>${CMAKE_STATIC_LIBRARY_SUFFIX})
else()
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
set(DEBUG_POSTFIX d)
endif()
set(gtest_LIBRARIES ${googletest_BINARY_DIR}/googletest/${CMAKE_STATIC_LIBRARY_PREFIX}gtest$<$<CONFIG:Debug>:d>${CMAKE_STATIC_LIBRARY_SUFFIX})
set(gtest_LIBRARIES ${EP_BASE}/lib/${CMAKE_STATIC_LIBRARY_PREFIX}gtest$<$<CONFIG:Debug>:d>${CMAKE_STATIC_LIBRARY_SUFFIX})
breznak marked this conversation as resolved.
Show resolved Hide resolved
endif()
FILE(APPEND "${EXPORT_FILE_NAME}" "gtest_INCLUDE_DIRS@@@${googletest_SOURCE_DIR}/googletest/include\n")
FILE(APPEND "${EXPORT_FILE_NAME}" "gtest_LIBRARIES@@@${gtest_LIBRARIES}\n")
Expand Down
9 changes: 7 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ cmake_minimum_required(VERSION 3.7)
project(htm_core CXX)

message(STATUS "Configuring htm_core src")
message(STATUS "Using MUSL LIBC= ${NTA_LIBC_MUSL}")
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CMAKE_VERBOSE_MAKEFILE ON) # toggle for cmake debug
include(src/NupicLibraryUtils) # for combining static libs
Expand Down Expand Up @@ -249,6 +250,9 @@ set(src_lib_static htm_core_solo)
add_library(${src_lib_static} STATIC $<TARGET_OBJECTS:${src_objlib}>)
if(MSVC)
set_property(TARGET ${src_lib_static} PROPERTY LINK_LIBRARIES ${INTERNAL_LINKER_FLAGS})
elseif(${NTA_LIBC_MUSL})
message("Doing static build with MUSL libc")
target_link_libraries(${src_lib_static} -static)
endif()
#
# Create the libhtm_core.a as a "combined" static library by merging htm_core_static
Expand Down Expand Up @@ -325,12 +329,13 @@ target_link_libraries(${src_executable_hotgym}
${core_library}
${COMMON_OS_LIBS}
)


# for future reference; to link to shared library, (Not on MSVC)
# link with ${src_lib_shared} rather than ${core_library}

target_compile_options( ${src_executable_hotgym} PUBLIC ${INTERNAL_CXX_FLAGS})
target_compile_definitions(${src_executable_hotgym} PRIVATE ${COMMON_COMPILER_DEFINITIONS})
target_compile_definitions(${src_executable_hotgym} PRIVATE ${COMMON_COMPILER_DEFINITIONS} -DNTA_LIBC_MUSL=${NTA_LIBC_MUSL})
breznak marked this conversation as resolved.
Show resolved Hide resolved
target_include_directories(${src_executable_hotgym} PRIVATE
${CORE_LIB_INCLUDES}
${EXTERNAL_INCLUDES}
Expand All @@ -354,7 +359,7 @@ else()
${COMMON_OS_LIBS}
)
target_compile_options( ${src_dyn_executable_hotgym} PUBLIC ${INTERNAL_CXX_FLAGS})
target_compile_definitions(${src_dyn_executable_hotgym} PRIVATE ${COMMON_COMPILER_DEFINITIONS})
target_compile_definitions(${src_dyn_executable_hotgym} PRIVATE ${COMMON_COMPILER_DEFINITIONS} -DNTA_LIBC_MUSL=${NTA_LIBC_MUSL})
target_include_directories(${src_dyn_executable_hotgym} PRIVATE
${CORE_LIB_INCLUDES}
${EXTERNAL_INCLUDES}
Expand Down
15 changes: 8 additions & 7 deletions src/examples/hotgym/HelloSPTP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ Real64 BenchmarkHotgym::run(UInt EPOCHS, bool useSPlocal, bool useSPglobal, bool
EPOCHS = 2; // make test faster in Debug
#endif

#if defined __aarch64__ || defined __arm__
#undef _ARCH_DETERMINISTIC
#else
#define _ARCH_DETERMINISTIC
#endif

if(useTM ) {
NTA_CHECK(useSPlocal or useSPglobal) << "using TM requires a SP too";
Expand Down Expand Up @@ -200,7 +195,11 @@ EPOCHS = 2; // make test faster in Debug

SDR goldSP({COLS});
const SDR_sparse_t deterministicSP{
#ifdef NTA_LIBC_MUSL
62, 72, 73, 82, 85, 102, 263, 277, 287, 303, 306, 308, 309, 322, 337, 339, 340, 352, 370, 493, 1094, 1095, 1114, 1115, 1120, 1463, 1512, 1518, 1647, 1651, 1691, 1694, 1729, 1745, 1746, 1760, 1770, 1774, 1775, 1781, 1797, 1798, 1803, 1804, 1805, 1812, 1827, 1828, 1831, 1832, 1858, 1859, 1860, 1861, 1862, 1875, 1878, 1880, 1881, 1898, 1918, 1923, 1929, 1931, 1936, 1950, 1953, 1956, 1958, 1961, 1964, 1965, 1967, 1971, 1973, 1975, 1976, 1979, 1980, 1981, 1982, 1984, 1985, 1986, 1988, 1991, 1994, 1996, 1997, 1998, 1999, 2002, 2006, 2008, 2011, 2012, 2013, 2017, 2019, 2022, 2027, 2030
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added custom deterministic results for MUSL. I don't know if we can achieve same on glibc & musl.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #707

#else
62, 72, 73, 82, 85, 102, 263, 277, 287, 303, 306, 308, 309, 322, 337, 339, 340, 352, 370, 493, 1094, 1095, 1114, 1115, 1120, 1463, 1512, 1518, 1647, 1651, 1691, 1694, 1729, 1745, 1746, 1760, 1770, 1774, 1775, 1781, 1797, 1798, 1803, 1804, 1805, 1812, 1827, 1828, 1831, 1832, 1858, 1859, 1860, 1861, 1862, 1875, 1878, 1880, 1881, 1898, 1918, 1923, 1929, 1931,1936, 1950, 1953, 1956, 1958, 1961, 1964, 1965, 1967, 1971, 1973, 1975, 1976, 1979, 1980, 1981, 1982, 1984, 1985, 1986, 1988, 1991, 1994, 1996, 1997, 1998, 1999, 2002, 2006, 2008, 2011, 2012, 2013, 2017, 2019, 2022, 2027, 2030
#endif
};
goldSP.setSparse(deterministicSP);

Expand All @@ -212,14 +211,17 @@ EPOCHS = 2; // make test faster in Debug

SDR goldTM({COLS});
const SDR_sparse_t deterministicTM{
#ifdef NTA_LIBC_MUSL
62, 77, 85, 322, 340, 432, 952, 1120, 1488, 1502, 1512, 1518, 1547, 1627, 1633, 1668, 1727, 1729, 1797, 1803, 1805, 1812, 1858, 1859, 1896, 1918, 1923, 1925, 1929, 1931, 1939, 1941, 1942, 1944, 1950, 1953, 1955, 1956, 1965, 1966, 1967, 1968, 1974, 1980, 1987, 1996, 2006, 2008, 2011, 2027, 2030, 2042, 2046
#else
62, 77, 85, 322, 340, 432, 952, 1120, 1488, 1502, 1512, 1518, 1547, 1627, 1633, 1668, 1727, 1729, 1797, 1803, 1805, 1812, 1858, 1859, 1896, 1918, 1923, 1925, 1929, 1931, 1939, 1941, 1942, 1944, 1950, 1953, 1955, 1956, 1965, 1966, 1967, 1968, 1974, 1980, 1987, 1996, 2006, 2008, 2011, 2027, 2030, 2042, 2046
#endif
};
goldTM.setSparse(deterministicTM);

const float goldAn = 0.627451f;
const float goldAnAvg = 0.407265f;

#ifdef _ARCH_DETERMINISTIC
if(EPOCHS == 5000) {
//these hand-written values are only valid for EPOCHS = 5000 (default), but not for debug and custom runs.
NTA_CHECK(input == goldEnc) << "Deterministic output of Encoder failed!\n" << input << "should be:\n" << goldEnc;
Expand All @@ -231,7 +233,6 @@ EPOCHS = 2; // make test faster in Debug
NTA_CHECK(static_cast<UInt>(avgAnom10.getCurrentAvg() * 10000.0f) == static_cast<UInt>(goldAnAvg * 10000.0f))
<< "Deterministic average anom score failed:" << avgAnom10.getCurrentAvg() << " should be: " << goldAnAvg;
}
#endif

// check runtime speed
const size_t timeTotal = (size_t)floor(tAll.getElapsed());
Expand Down
2 changes: 1 addition & 1 deletion src/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ target_include_directories(${unit_tests_executable} PRIVATE
${gtest_INCLUDE_DIRS}
${CORE_LIB_INCLUDES}
${EXTERNAL_INCLUDES})
target_compile_definitions(${unit_tests_executable} PRIVATE ${COMMON_COMPILER_DEFINITIONS})
target_compile_definitions(${unit_tests_executable} PRIVATE ${COMMON_COMPILER_DEFINITIONS} -DNTA_LIBC_MUSL=${NTA_LIBC_MUSL})
target_compile_options(${unit_tests_executable} PUBLIC ${INTERNAL_CXX_FLAGS})
add_dependencies(${unit_tests_executable} ${core_library})
#add_dependencies(${unit_tests_executable} ${src_lib_shared})
Expand Down
27 changes: 7 additions & 20 deletions src/test/unit/algorithms/SpatialPoolerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2057,23 +2057,18 @@ TEST(SpatialPoolerTest, testConstructorVsInitialize) {
TEST(SpatialPoolerTest, ExactOutput) {
// Silver is an SDR that is loaded by direct initalization from a vector.
SDR silver_sdr({ 200 });
#ifdef NTA_LIBC_MUSL
SDR_sparse_t data = {
4, 6, 17, 85, 113, 125, 133, 153, 172, 173
};
#else
SDR_sparse_t data = {
4, 64, 74, 78, 85, 113, 125, 126, 127, 153
};
#endif
silver_sdr.setSparse(data);


// Gold tests initalizing an SDR from a manually created string in JSON format.
// hint: you can generate this string using
// silver_sdr.save(std::cout, JSON);
string gold = "{\"dimensions\": [200],\"sparse\": [4, 64, 74, 78, 85, 113, 125, 126, 127, 153]}";
std::stringstream gold_stream( gold );
SDR gold_sdr;
gold_sdr.load( gold_stream, JSON );

// both SCR's should be the same
EXPECT_EQ(silver_sdr, gold_sdr);

SDR inputs({ 1000 });
SDR columns({ 200 });
SpatialPooler sp({inputs.dimensions}, {columns.dimensions},
Expand All @@ -2098,15 +2093,7 @@ TEST(SpatialPoolerTest, ExactOutput) {
sp.compute(inputs, true, columns);
}

#if defined __aarch64__ || defined __arm__
#undef _ARCH_DETERMINISTIC
#else
#define _ARCH_DETERMINISTIC
#endif

#ifdef _ARCH_DETERMINISTIC
ASSERT_EQ( columns, gold_sdr );
#endif
ASSERT_EQ( columns, silver_sdr );
}


Expand Down