Newer
Older
# Copyright (c) 2015-2016, Luca Fulchir<luca@fulchir.it>, All rights reserved.
#
# This file is part of "libRaptorQ".
#
# libRaptorQ is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation, either version 3
# of the License, or (at your option) any later version.
#
# libRaptorQ is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# and a copy of the GNU Lesser General Public License
# along with libRaptorQ. If not, see <http://www.gnu.org/licenses/>.
project (libRaptorQ)
enable_language(CXX)
enable_language(C)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake; ${CMAKE_MODULE_PATH})
message(STATUS "libRaptorQ version ${RQ_VERSION}")
add_definitions(-DRQ_VERSION="${RQ_VERSION}")
include(GNUInstallDirs)
option(DYNAMIC_LIB "Build dynamic library" ON)
option(STATIC_LIB "Build static library" ON)
option(CLANG_STDLIB "Use clang's libc++" OFF)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build Type")
set(USE_LZ4 "ON" CACHE STRING "Use LZ4 compression for result caching")
set(RQ_LINKER CACHE STRING "linker to use (auto/gold/ld/bsd)")
set(RQ_ENDIANNESS CACHE STRING "endianness of your system")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel)
set_property(CACHE USE_LZ4 PROPERTY STRINGS ON BUNDLED OFF)
set_property(CACHE RQ_ENDIANNESS PROPERTY STRINGS Auto BigEndian LittleEndian)
mark_as_advanced(FORCE RQ_LINKER RQ_ENDIANNESS RQ_GOLD RQ_LZ4_LIB)
if (USE_LZ4 MATCHES "BUNDLED")
set(USE_LZ4 "ON")
set(RQ_LZ4_USE_OWN TRUE)
endif()
if (NOT RQ_ENDIANNESS)
set(RQ_ENDIANNESS Auto)
endif()
if (RQ_ENDIANNESS MATCHES "Auto")
include(TestBigEndian)
TEST_BIG_ENDIAN(IS_BIG_ENDIAN)
if (IS_BIG_ENDIAN)
add_definitions(-DRQ_BIG_ENDIAN)
message (STATUS "Detected big endian machine")
else()
add_definitions(-DRQ_LITTLE_ENDIAN)
message (STATUS "Detected little endian machine")
endif()
elseif (RQ_ENDIANNESS MATCHES "BigEndian")
add_definitions(-DRQ_BIG_ENDIAN)
message (STATUS "Forced to big endian")
elseif (RQ_ENDIANNESS MATCHES "LittleEndian")
add_definitions(-DRQ_LITTLE_ENDIAN)
message (STATUS "Forced to little endian")
endif()
# supported linkers: gold, linux standard, bsd
if(NOT RQ_LINKER)
if(CMAKE_SYSTEM_NAME MATCHES "Darwin" OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "Windows")
set(RQ_LINKER BSD)
else()
find_program(RQ_GOLD ld.gold)
if (NOT RQ_GOLD MATCHES "RQ_GOLD-NOTFOUND")
set(RQ_LINKER GOLD)
else()
set(RQ_LINKER LD)
endif()
endif()
endif()
if(RQ_LINKER MATCHES GOLD)
message(STATUS "Using the GOLD linker")
elseif(RQ_LINKER MATCHES LD)
message(STATUS "Using the LD linker")
elseif(RQ_LINKER MATCHES BSD)
message(STATUS "Using the BSD linker")
else()
message(WARNING "Linker not found? Default no option.")
set(RQ_LINKER BSD)
endif()
# defaults: only enable LTO/PROFILING with known compilers
# exception: osx/BSD. llvm linker/profiling not default?
if ((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") AND
(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin") AND (NOT ${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD"))
option(LTO "Link Time Optimization" ON)
option(PROFILING "Profiling: speedup library" ON)
option(LTO "Link Time Optimization" OFF)
option(PROFILING "Profiling: speedup library" OFF)
message(STATUS "Build selected: ${CMAKE_BUILD_TYPE}")
if(NOT (STATIC_LIB MATCHES "ON"))
if (NOT (DYNAMIC_LIB MATCHES "ON"))
message(FATAL_ERROR "Do you want to actually build the library?")
endif()
endif()
if(LTO MATCHES "ON")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
find_program(RQ_AR "llvm-ar")
find_program(RQ_NM "llvm-nm")
find_program(RQ_RANLIB "llvm-ranlib")
find_program(RQ_LLVM_PROF llvm-profdata)
mark_as_advanced(FORCE RQ_LLVM_PROF)
if (RQ_LLVM_PROF MATCHES "RQ_LLVM_PROF-NOTFOUND")
message(FATAL_ERROR "Profiling support with clang requires \"llvm-profdata\". Disable profiling with cmake option \"-DPROFILING=OFF\"")
endif()
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
find_program(RQ_AR "gcc-ar")
find_program(RQ_NM "gcc-nm")
find_program(RQ_RANLIB "gcc-ranlib")
endif()
# check if we found the linker
if (RQ_AR STREQUAL "RQ_AR-NOTFOUND" OR RQ_NM STREQUAL "RQ_NM-NOTFOUND" OR RQ_RANLIB STREQUAL "RQ_RANLIB-NOTFOUND")
message(FATAL_ERROR "Can't find the linker programs. Please disable LTO with cmake option \"-DLTO=OFF\"")
set(CMAKE_AR ${RQ_AR})
set(CMAKE_NM ${RQ_NM})
set(CMAKE_RANLIB ${RQ_RANLIB})
mark_as_advanced(FORCE RQ_AR RQ_NM RQ_RANLIB)
else()
message(FATAL_ERROR "Sorry, don't know how to do LTO with your compiler")
endif()
else()
endif()
# Profiling is pretty compiler-specific....
if(PROFILING MATCHES "ON")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU")
message(STATUS "Profiling activated")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
message(WARNING "Clang's profile support breaks deterministic builds!")
endif()
else()
message(FATAL_ERROR "Sorry, don't know how to profile with your compiler")
endif()
else()
message(STATUS "Profiling deactivated")
endif()
if(CLANG_STDLIB MATCHES "ON")
if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
message(FATAL_ERROR "libc++ is only supported by clang")
endif()
if(CLANG_STDLIB MATCHES "ON")
set(RQ_STDLIB_FLAG -stdlib=libc++)
set(STDLIB c++)
else()
set(STDLIB stdc++)
endif()
find_package(Threads REQUIRED)
find_package(git)
find_package(eigen REQUIRED)
include_directories(SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIR})
include_directories(SYSTEM PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/external/optionparser-1.4")
include_directories(SYSTEM PUBLIC ${RQ_LZ4_INCLUDE_DIR})
include(${CMAKE_CURRENT_SOURCE_DIR}/external/build_deps.cmake)
if (CLI MATCHES "ON")
message(STATUS "Building CLI tools")
else()
message(STATUS "NOT Building CLI tools")
endif()
# our include tree
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src)
if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/.git/ AND GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --sq HEAD OUTPUT_VARIABLE RQ_SEED)
set(RQ_SEED RaptorQ_nongit_v${RQ_VERSION})
message(WARNING "Not inside a git repository. Compiler seed is now constant.")
endif()
set(DETERMINISTIC -frandom-seed=${RQ_SEED})
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
add_definitions(-DRQ_WINDOWS)
message(WARNING, "RaptorQ builds are not deterministic in Windows yet")
else()
add_definitions(-DRQ_UNIX)
endif()
src/RaptorQ/v1/wrapper/C_RFC_API.cpp
src/RaptorQ/v1/wrapper/CPP_RAW_API_void.cpp
src/RaptorQ/v1/wrapper/CPP_RFC_API_void.cpp
src/RaptorQ/v1/common.hpp
src/RaptorQ/v1/De_Interleaver.hpp
src/RaptorQ/v1/Decoder.hpp
src/RaptorQ/v1/degree.hpp
src/RaptorQ/v1/Interleaver.hpp
src/RaptorQ/v1/multiplication.hpp
src/RaptorQ/v1/Operation.hpp
src/RaptorQ/v1/Parameters.hpp
src/RaptorQ/v1/Precode_Matrix.hpp
src/RaptorQ/v1/Precode_Matrix_Init.hpp
src/RaptorQ/v1/Precode_Matrix_Solver.hpp
src/RaptorQ/v1/RaptorQ.hpp
src/RaptorQ/v1/RaptorQ_Iterators.hpp
src/RaptorQ/v1/RFC_Iterators.hpp
src/RaptorQ/v1/Shared_Computation/Decaying_LF.hpp
src/RaptorQ/v1/table2.hpp
src/RaptorQ/v1/util/Bitmask.hpp
src/RaptorQ/v1/util/div.hpp
src/RaptorQ/RaptorQ.h
src/RaptorQ/RaptorQ_v1.hpp
src/RaptorQ/RFC6330.h
src/RaptorQ/v1/wrapper/C_RFC_API.h
src/RaptorQ/v1/wrapper/CPP_RFC_API.hpp
src/RaptorQ/v1/wrapper/CPP_RFC_API_void.hpp
src/RaptorQ/v1/wrapper/CPP_RAW_API.hpp
src/RaptorQ/v1/wrapper/CPP_RAW_API_void.hpp
)
SET(HEADERS_ONLY
src/RaptorQ/RaptorQ_v1_hdr.hpp
src/RaptorQ/RFC6330_v1_hdr.hpp
)
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
# windows-only placeholder
else()
# linux-only placeholder
endif()
if (USE_LZ4 MATCHES "ON")
SET (HEADERS ${HEADERS}
src/RaptorQ/v1/Shared_Computation/LZ4_Wrapper.hpp)
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_definitions(-DUSING_CLANG)
set(LD_OPT "-flto -fuse-ld=gold" )
else()
set(LD_OPT "-flto" )
endif()
endif()
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(LD_OPT "")
endif()
########################################
## TODO: if windows, add notelemetry.obj
########################################
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PROFILE_GET -fprofile-instr-generate)
set(PROFILE_GET_FILE RaptorQ.profraw)
set(PROFILE_SET_FILE RaptorQ.profdata)
set(PROFILE_SET "-fprofile-instr-use=${PROFILE_SET_FILE}")
set(PROFILE_GET -fprofile-generate)
# gcc creates a couple more files than clang for prifiling. Track them.
set(PROFILE_GET_FILE
CMakeFiles/test_c_profiled.dir/test/test_c.c.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Shared_Computation/Decaying_LF.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Graph.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Rand.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Operation.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/RFC.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Precode_Matrix_Instantiation.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Parameters.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Bitmask.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/Thread_Pool.cpp.gcda
CMakeFiles/RaptorQ_Static_Profiling.dir/src/RaptorQ/v1/API_Wrapper_C.cpp.gcda)
set(PROFILE_SET_FILE ${PROFILE_GET_FILE})
set(PROFILE_SET -fprofile-use)
endif()
# PRE-run: build a library, generate the profile.
add_library(RaptorQ_Static_Profiling STATIC ${SOURCES} ${HEADERS} ${HEADERS_LINKED})
target_link_libraries(RaptorQ_Static_Profiling ${STDLIB} ${RQ_LZ4_DEP} ${RQ_UBSAN})
target_compile_options(
RaptorQ_Static_Profiling PRIVATE
${CXX_COMPILER_FLAGS}
)
set_target_properties(RaptorQ_Static_Profiling PROPERTIES COMPILER_FLAGS ${PROFILE_GET})
# build the C example test for profiling
add_executable(test_c_profiled test/test_c.c)
add_dependencies(test_c_profiled RaptorQ_Static_Profiling)
target_compile_options(
test_c_profiled PRIVATE
${C_COMPILER_FLAGS}
target_link_libraries(test_c_profiled RaptorQ_Static_Profiling ${STDLIB} m ${CMAKE_THREAD_LIBS_INIT} ${RQ_UBSAN})
target_link_libraries(test_c_profiled RaptorQ_Static_Profiling ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_UBSAN})
set_target_properties(test_c_profiled PROPERTIES LINK_FLAGS ${PROFILE_GET})
add_custom_command(
OUTPUT ${PROFILE_GET_FILE}
COMMAND LLVM_PROFILE_FILE=${PROFILE_GET_FILE} ./test_c_profiled
DEPENDS test_c_profiled
COMMENT "Running profiling test..."
VERBATIM
)
add_custom_command(
OUTPUT ${PROFILE_GET_FILE}
COMMAND ./test_c_profiled
DEPENDS test_c_profiled
COMMENT "Running profiling test..."
VERBATIM
)
endif()
# the profile must be translated into readable form
add_custom_command(
OUTPUT ${PROFILE_SET_FILE}
COMMAND llvm-profdata merge -output=${PROFILE_SET_FILE} ${PROFILE_GET_FILE}
DEPENDS ${PROFILE_GET_FILE}
COMMENT "Creating profile data..."
VERBATIM
)
endif()
add_custom_target(
profile ALL
DEPENDS ${PROFILE_SET_FILE}
)
endif()
# build the static library
if(STATIC_LIB MATCHES "ON")
add_library(RaptorQ_Static STATIC ${SOURCES} ${HEADERS} ${HEADERS_LINKED})
set_target_properties(RaptorQ_Static PROPERTIES OUTPUT_NAME RaptorQ.${RQ_ABI})
endif()
target_compile_options(
RaptorQ_Static PRIVATE
${CXX_COMPILER_FLAGS}
)
if(LTO MATCHES "ON")
endif()
if(PROFILING MATCHES "ON")
add_dependencies(RaptorQ_Static profile)
target_compile_options(RaptorQ_Static PRIVATE ${PROFILE_SET})
endif()
if (NOT RQ_LINKER MATCHES BSD)
set_target_properties (
RaptorQ_Static
PROPERTIES
LINK_FLAGS "-Wl,-z,now,-z,relro${RQ_LZ4_EXCLUDE_SYM} -pie ${LD_OPT}"
set_property(TARGET RaptorQ_Static PROPERTY ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
# not really deterministic?
# don't know how to do that in Windows.
add_custom_target(
make_static_deterministic ALL
DEPENDS RaptorQ_Static
)
else()
# make the library deterministic (only on *nix)
add_executable(make_deterministic src/deterministic.cpp)
target_compile_options(
make_deterministic PRIVATE
${CXX_COMPILER_FLAGS}
)
target_link_libraries(make_deterministic ${STDLIB} ${RQ_UBSAN})
add_custom_command(
OUTPUT deterministic.run
COMMAND make_deterministic ${CMAKE_CURRENT_BINARY_DIR}/lib/libRaptorQ.${RQ_ABI}.a
DEPENDS RaptorQ_Static
COMMENT "Removing creation date from library..."
VERBATIM
)
add_custom_target(
make_static_deterministic ALL
DEPENDS deterministic.run
)
endif()
#build dynamic library
if(DYNAMIC_LIB MATCHES "ON")
add_definitions(-DRAPTORQ_DLL)
add_definitions(-DRAPTORQ_DLL_EXPORTS)
add_library(RaptorQ SHARED ${SOURCES} ${HEADERS} ${HEADERS_LINKED})
target_compile_options(
RaptorQ PRIVATE
${CXX_COMPILER_FLAGS}
)
if(LTO MATCHES "ON")
endif()
if(PROFILING MATCHES "ON")
add_dependencies(RaptorQ profile)
target_compile_options(RaptorQ PRIVATE ${PROFILE_SET})
endif()
if (RQ_LINKER MATCHES BSD)
# keep the last sace at the end here, otherwise cmake gets called
# with the wrong number of parameters in the next set_target_properties
set(RQ_LINK_LIB "${LD_OPT} ")
else()
set(RQ_LINK_LIB "-Wl,-z,now,-z,relro${RQ_LZ4_EXCLUDE_SYM} ${LD_OPT}")
set_property(TARGET RaptorQ PROPERTY LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
add_executable(libRaptorQ-test EXCLUDE_FROM_ALL test/rfc_test.cpp ${HEADERS_ONLY} ${HEADERS})
target_link_libraries(libRaptorQ-test ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
# Linux, *BSD
target_link_libraries(test_c RaptorQ m ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
else()
# windows: no "m" library
target_link_libraries(test_c RaptorQ ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
# CPP interface - RFC interface (header only)
add_executable(test_cpp_rfc EXCLUDE_FROM_ALL test/test_cpp_rfc.cpp ${HEADERS_ONLY} ${HEADERS})
target_link_libraries(test_cpp_rfc ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
# CPP interface - RFC interface (linked version)
add_executable(test_cpp_rfc_linked EXCLUDE_FROM_ALL test/test_cpp_rfc.cpp ${HEADERS_ONLY} ${HEADERS})
target_compile_options(
test_cpp_rfc_linked PRIVATE
${CXX_COMPILER_FLAGS}
)
add_dependencies(test_cpp_rfc_linked RaptorQ)
target_link_libraries(test_cpp_rfc_linked RaptorQ ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
# CPP interface - RAW interface (header only)
add_executable(test_cpp_raw EXCLUDE_FROM_ALL test/test_cpp_raw.cpp ${HEADERS_ONLY} ${HEADERS})
${CXX_COMPILER_FLAGS} "-DTEST_HDR_ONLY"
)
target_link_libraries(test_cpp_raw RaptorQ ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
# CPP interface - RAW interface (linked version)
add_executable(test_cpp_raw_linked EXCLUDE_FROM_ALL test/test_cpp_raw.cpp)
target_compile_options(
test_cpp_raw_linked PRIVATE
add_dependencies(test_cpp_raw_linked RaptorQ)
target_link_libraries(test_cpp_raw_linked RaptorQ ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
# CLI tool - RAW API interface (header only)
set(CLI_raw_sources src/cli/RaptorQ.cpp external/optionparser-1.4/optionparser.h ${HEADERS} ${HEADERS_ONLY})
if(CLI MATCHES "ON")
add_executable(CLI_raw ${CLI_raw_sources})
add_custom_target(CLI_tools DEPENDS CLI_raw)
else()
add_executable(CLI_raw EXCLUDE_FROM_ALL ${CLI_raw_sources})
add_custom_target(CLI_tools "")
endif()
target_link_libraries(CLI_raw ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
# CPP interface - RAW interface (header only)
add_executable(example_cpp_raw EXCLUDE_FROM_ALL examples/example_cpp_raw.cpp ${HEADERS_ONLY} ${HEADERS})
target_compile_options(
example_cpp_raw PRIVATE
${CXX_COMPILER_FLAGS}
)
target_link_libraries(example_cpp_raw ${RQ_UBSAN} ${STDLIB} ${CMAKE_THREAD_LIBS_INIT} ${RQ_LZ4_DEP})
add_custom_target(examples DEPENDS test_c test_cpp_rfc test_cpp_rfc_linked test_cpp_raw test_cpp_raw_linked libRaptorQ-test example_cpp_raw)
add_custom_target(everything DEPENDS make_static_deterministic examples docs CLI_tools)
foreach (hdr ${HEADERS} ${HEADERS_ONLY} ${HEADERS_LINKED})
get_filename_component (full_dir_of_file ${hdr} PATH)
# remove the initial "src/":
string (SUBSTRING ${full_dir_of_file} 4 -1 dir_of_file)
install (FILES ${hdr} DESTINATION "include/${dir_of_file}")
endforeach()
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib COMPONENT libraries)