Skip to content

Commit

Permalink
#7: CMake: add project
Browse files Browse the repository at this point in the history
Add a CMake project for this library.

This patchset by @BurningEnlightenment has been maintained off-tree for
a long time, and people have come to rely on it, so time has come to
merge it into the mainline and make it 'official'.

The consensus is that the CMake scripts in this patchset could probably
be improved (see the issue's discussion on GitHub for details), but
because this patchset already represents significant value to those who
depend on it, it is best to merge it now and iterate as needed inside
this repo.

Many thanks for all contributors and their tremendous patience.

Closes #7.
  • Loading branch information
aklomp committed May 10, 2022
2 parents eaebee8 + 61a8bee commit f8fc217
Show file tree
Hide file tree
Showing 18 changed files with 491 additions and 15 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,10 @@ bin/base64
lib/config.h
test/benchmark
test/test_base64

# visual studio symbol db, etc.
.vs/
# build directory used by CMakePresets
out/
# private cmake presets
CMakeUserPresets.json
264 changes: 264 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
# Written in 2016-2017, 2021 by Henrik Steffen Gaßmann henrik@gassmann.onl
#
# To the extent possible under law, the author(s) have dedicated all
# copyright and related and neighboring rights to this software to the
# public domain worldwide. This software is distributed without any warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication
# along with this software. If not, see
#
# http://creativecommons.org/publicdomain/zero/1.0/
#
########################################################################
cmake_minimum_required(VERSION 3.1)

project(base64 LANGUAGES C VERSION 0.4.0)

include(GNUInstallDirs)
include(CMakeDependentOption)
include(FeatureSummary)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules")

#######################################################################
# platform detection
include(TargetArch)
detect_target_architecture(_TARGET_ARCH)


###################################################################
# optional/conditional dependencies
find_package(OpenMP)
set_package_properties(OpenMP PROPERTIES
TYPE OPTIONAL
PURPOSE "Allows to utilize OpenMP"
)


########################################################################
# Compilation options
option(BASE64_WERROR "Treat warnings as error" ON)
option(BASE64_BUILD_TESTS "add test projects" ON)
cmake_dependent_option(BASE64_WITH_OpenMP "use OpenMP" OFF "OpenMP_FOUND" OFF)
add_feature_info("OpenMP codec" BASE64_WITH_OpenMP "spreads codec work accross multiple threads")
cmake_dependent_option(BASE64_REGENERATE_TABLES "regenerate the codec tables" OFF "NOT CMAKE_CROSSCOMPILING" OFF)

set(_IS_X86 "\"${_TARGET_ARCH}\" STREQUAL \"x86\" OR \"${_TARGET_ARCH}\" STREQUAL \"x64\"")
cmake_dependent_option(BASE64_WITH_SSSE3 "add SSSE 3 codepath" ON ${_IS_X86} OFF)
add_feature_info(SSSE3 BASE64_WITH_SSSE3 "add SSSE 3 codepath")
cmake_dependent_option(BASE64_WITH_SSE41 "add SSE 4.1 codepath" ON ${_IS_X86} OFF)
add_feature_info(SSE4.1 BASE64_WITH_SSE41 "add SSE 4.1 codepath")
cmake_dependent_option(BASE64_WITH_SSE42 "add SSE 4.2 codepath" ON ${_IS_X86} OFF)
add_feature_info(SSE4.2 BASE64_WITH_SSE42 "add SSE 4.2 codepath")
cmake_dependent_option(BASE64_WITH_AVX "add AVX codepath" ON ${_IS_X86} OFF)
add_feature_info(AVX BASE64_WITH_AVX "add AVX codepath")
cmake_dependent_option(BASE64_WITH_AVX2 "add AVX 2 codepath" ON ${_IS_X86} OFF)
add_feature_info(AVX2 BASE64_WITH_AVX2 "add AVX2 codepath")

set(_IS_ARM "\"${_TARGET_ARCH}\" STREQUAL \"arm\"")
cmake_dependent_option(BASE64_WITH_NEON32 "add NEON32 codepath" OFF ${_IS_ARM} OFF)
add_feature_info(NEON32 BASE64_WITH_NEON32 "add NEON32 codepath")

set(_IS_ARM64 "\"${_TARGET_ARCH}\" STREQUAL \"arm64\"")
cmake_dependent_option(BASE64_WITH_NEON64 "add NEON64 codepath" ON ${_IS_ARM64} OFF)
add_feature_info(NEON64 BASE64_WITH_NEON64 "add NEON64 codepath")

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")

########################################################################
# Regenerate headers

if (BASE64_REGENERATE_TABLES)
# Generate tables in build folder and copy to source tree.
# Don't add the tables in the source tree to the outputs, to avoid `make clean` removing them.
add_executable(table_generator
lib/tables/table_generator.c
)

add_custom_command(OUTPUT table_dec_32bit.h "${CMAKE_CURRENT_SOURCE_DIR}/lib/tables/table_dec_32bit.h"
COMMAND table_generator > table_dec_32bit.h
COMMAND "${CMAKE_COMMAND}" -E copy table_dec_32bit.h "${CMAKE_CURRENT_SOURCE_DIR}/lib/tables/table_dec_32bit.h"
DEPENDS table_generator
)
set(Python_ADDITIONAL_VERSIONS 3)
find_package(PythonInterp REQUIRED)
add_custom_command(OUTPUT table_enc_12bit.h "${CMAKE_CURRENT_SOURCE_DIR}/lib/tables/table_enc_12bit.h"
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/lib/tables/table_enc_12bit.py" > table_enc_12bit.h
COMMAND "${CMAKE_COMMAND}" -E copy table_enc_12bit.h "${CMAKE_CURRENT_SOURCE_DIR}/lib/tables/table_enc_12bit.h"
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/lib/tables/table_enc_12bit.py"
)
endif()


########################################################################
# library project
add_library(base64
# library files
lib/lib.c
lib/codec_choose.c
include/libbase64.h

lib/tables/tables.c
# Add generated headers explicitly to target, to insert them in the dependency tree
lib/tables/table_dec_32bit.h
lib/tables/table_enc_12bit.h

# codec implementations
lib/arch/generic/codec.c

lib/arch/ssse3/codec.c
lib/arch/sse41/codec.c
lib/arch/sse42/codec.c
lib/arch/avx/codec.c
lib/arch/avx2/codec.c

lib/arch/neon32/codec.c
lib/arch/neon64/codec.c
)

target_include_directories(base64
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
PRIVATE
"${CMAKE_CURRENT_BINARY_DIR}"
)

####################################################################
# platform/compiler specific configuration
set_target_properties(base64 PROPERTIES
C_STANDARD 99
C_STANDARD_REQUIRED YES
C_EXTENSIONS OFF
DEFINE_SYMBOL BASE64_EXPORTS
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)

#generate_export_header(base64)
# the following definitions and those in libbase64.h have been
# kept forward compatible in case we ever switch to generate_export_header
if (BUILD_SHARED_LIBS)
set_target_properties(base64 PROPERTIES
C_VISIBILITY_PRESET hidden
)
else()
target_compile_definitions(base64
PUBLIC
BASE64_STATIC_DEFINE
)
endif()

target_compile_options(base64 PRIVATE
$<$<C_COMPILER_ID:MSVC>:
/W4
/we4013 # Error warning C4013: 'function' undefined; assuming extern returning int
/we4700 # Error warning C4700: uninitialized local variable
/we4715 # not all control paths return a value
/we4003 # not enough actual parameters for macro
/wd4456 # disable warning C4456: declaration of 'xxx' hides previous local declaration
>
$<$<NOT:$<C_COMPILER_ID:MSVC>>:
-Wall
-Wextra
-Wpedantic
>
$<$<BOOL:${BASE64_WERROR}>:$<IF:$<C_COMPILER_ID:MSVC>,/WX,-Werror>>
)

target_compile_definitions(base64 PRIVATE
$<$<C_COMPILER_ID:MSVC>:
# remove unnecessary warnings about unchecked iterators
_SCL_SECURE_NO_WARNINGS
>
)

########################################################################
# SIMD settings
include(TargetSIMDInstructionSet)
define_SIMD_compile_flags()

if (_TARGET_ARCH STREQUAL "x86" OR _TARGET_ARCH STREQUAL "x64")
macro(configure_codec _TYPE)
if (BASE64_WITH_${_TYPE})
message(STATUS "Add codec: lib/arch/${_DIR}/codec.c")
string(TOLOWER "${_TYPE}" _DIR)
set_source_files_properties("lib/arch/${_DIR}/codec.c" PROPERTIES
COMPILE_FLAGS "${COMPILE_FLAGS_${_TYPE}}"
)

if (${ARGC} GREATER 1 AND MSVC)
set_source_files_properties("lib/arch/${_DIR}/codec.c" PROPERTIES
COMPILE_DEFINITIONS ${ARGV1}
)
endif()
endif()
endmacro()

configure_codec(SSSE3 __SSSE3__)
configure_codec(SSE41 __SSSE4_1__)
configure_codec(SSE42 __SSSE4_2__)
configure_codec(AVX)
configure_codec(AVX2)

elseif (_TARGET_ARCH STREQUAL "arm")
set(BASE64_NEON32_CFLAGS "${COMPILE_FLAGS_NEON32}" CACHE STRING "the NEON32 compile flags (for 'lib/arch/neon32/codec.c')")
mark_as_advanced(BASE64_NEON32_CFLAGS)

if (BASE64_WITH_NEON32)
set_source_files_properties("lib/arch/neon32/codec.c" PROPERTIES
COMPILE_FLAGS "${BASE64_NEON32_CFLAGS} "
)
endif()

#elseif (_TARGET_ARCH STREQUAL "arm64" AND BASE64_WITH_NEON64)

endif()

configure_file("${CMAKE_CURRENT_LIST_DIR}/cmake/config.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)

########################################################################
# OpenMP Settings
if (BASE64_WITH_OpenMP)
target_compile_options(base64
PRIVATE
${OpenMP_C_FLAGS}
)
endif()

########################################################################
if (BASE64_BUILD_TESTS)
enable_testing()
add_subdirectory(test)
endif()

########################################################################
# cmake install
install(DIRECTORY include/ TYPE INCLUDE)
install(TARGETS base64 EXPORT base64-targets)

include(CMakePackageConfigHelpers)
configure_package_config_file(cmake/base64-config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/base64-config.cmake"

INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/base64-config-version.cmake"
VERSION ${BASE64_VERSION}
COMPATIBILITY SameMajorVersion
)

install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/base64-config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/base64-config-version.cmake"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)

install(EXPORT base64-targets
NAMESPACE aklomp::
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}"
)

########################################################################
feature_summary(WHAT PACKAGES_FOUND PACKAGES_NOT_FOUND ENABLED_FEATURES DISABLED_FEATURES)
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ lib/config.h:
@echo "#define HAVE_AVX $(HAVE_AVX)" >> $@

$(OBJS): lib/config.h
$(OBJS): CFLAGS += -Ilib

lib/arch/avx2/codec.o: CFLAGS += $(AVX2_CFLAGS)
lib/arch/neon32/codec.o: CFLAGS += $(NEON32_CFLAGS)
Expand Down
29 changes: 29 additions & 0 deletions cmake/Modules/TargetArch.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Written in 2017 by Henrik Steffen Gaßmann henrik@gassmann.onl
#
# To the extent possible under law, the author(s) have dedicated all
# copyright and related and neighboring rights to this software to the
# public domain worldwide. This software is distributed without any warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication
# along with this software. If not, see
#
# http://creativecommons.org/publicdomain/zero/1.0/
#
########################################################################

set(TARGET_ARCHITECTURE_TEST_FILE "${CMAKE_CURRENT_LIST_DIR}/../test-arch.c")

function(detect_target_architecture OUTPUT_VARIABLE)
message(STATUS "${CMAKE_CURRENT_LIST_DIR}")
try_compile(_IGNORED "${CMAKE_CURRENT_BINARY_DIR}"
"${TARGET_ARCHITECTURE_TEST_FILE}"
OUTPUT_VARIABLE _LOG
)

string(REGEX MATCH "##arch=([^#]+)##" _IGNORED "${_LOG}")

set(${OUTPUT_VARIABLE} "${CMAKE_MATCH_1}" PARENT_SCOPE)
if (CMAKE_MATCH_1 STREQUAL "unknown")
message(WARNING "could not detect the target architecture.")
endif()
endfunction()
34 changes: 34 additions & 0 deletions cmake/Modules/TargetSIMDInstructionSet.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Written in 2016-2017 by Henrik Steffen Gaßmann henrik@gassmann.onl
#
# To the extent possible under law, the author(s) have dedicated all
# copyright and related and neighboring rights to this software to the
# public domain worldwide. This software is distributed without any warranty.
#
# You should have received a copy of the CC0 Public Domain Dedication
# along with this software. If not, see
#
# http://creativecommons.org/publicdomain/zero/1.0/
#
########################################################################

########################################################################
# compiler flags definition
macro(define_SIMD_compile_flags)
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
# x86
set(COMPILE_FLAGS_SSSE3 "-mssse3")
set(COMPILE_FLAGS_SSE41 "-msse4.1")
set(COMPILE_FLAGS_SSE42 "-msse4.2")
set(COMPILE_FLAGS_AVX "-mavx")
set(COMPILE_FLAGS_AVX2 "-mavx2")

#arm
set(COMPILE_FLAGS_NEON32 "-mfpu=neon")
elseif(MSVC)
set(COMPILE_FLAGS_SSSE3 " ")
set(COMPILE_FLAGS_SSE41 " ")
set(COMPILE_FLAGS_SSE42 " ")
set(COMPILE_FLAGS_AVX "/arch:AVX")
set(COMPILE_FLAGS_AVX2 "/arch:AVX2")
endif()
endmacro(define_SIMD_compile_flags)
5 changes: 5 additions & 0 deletions cmake/base64-config.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/base64-targets.cmake")

check_required_components(base64)
25 changes: 25 additions & 0 deletions cmake/config.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef BASE64_CONFIG_H
#define BASE64_CONFIG_H

#cmakedefine01 BASE64_WITH_SSSE3
#define HAVE_SSSE3 BASE64_WITH_SSSE3

#cmakedefine01 BASE64_WITH_SSE41
#define HAVE_SSE41 BASE64_WITH_SSE41

#cmakedefine01 BASE64_WITH_SSE42
#define HAVE_SSE42 BASE64_WITH_SSE42

#cmakedefine01 BASE64_WITH_AVX
#define HAVE_AVX BASE64_WITH_AVX

#cmakedefine01 BASE64_WITH_AVX2
#define HAVE_AVX2 BASE64_WITH_AVX2

#cmakedefine01 BASE64_WITH_NEON32
#define HAVE_NEON32 BASE64_WITH_NEON32

#cmakedefine01 BASE64_WITH_NEON64
#define HAVE_NEON64 BASE64_WITH_NEON64

#endif // BASE64_CONFIG_H
Loading

0 comments on commit f8fc217

Please sign in to comment.