Skip to content

Commit

Permalink
CMAKE BUILDSYSTEM OVERHAUL
Browse files Browse the repository at this point in the history
Adapt the build system to the recent source code changes.

Add platform detection code for arm, arm64, x86 and x64. Offer SIMD
compile options depending on platform. Add preliminary support for NEON
codecs. Enable the SIMD compile options by default.

- Clean cmake scripts.
- Bump version to 0.3.0.
- Fix UTF-8 issues.
  • Loading branch information
BurningEnlightenment committed Feb 16, 2017
1 parent cf05304 commit 0d41483
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 157 deletions.
195 changes: 104 additions & 91 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Written in 2016 by Henrik Steffen Ga�mann henrik@gassmann.onl
# 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
Expand All @@ -12,7 +12,7 @@
########################################################################
cmake_minimum_required(VERSION 2.8.12)
project(base64)
set(BASE64_VERSION 0.2.1)
set(BASE64_VERSION 0.3.0)

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules")

Expand All @@ -25,118 +25,131 @@ if (CMAKE_C_COMPILER_ID STREQUAL "GNU"
set(BASE64_GNU_CXX_COMPATIBLE 1)
endif()


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


########################################################################
# Compilation options
#
# set BASE64_INCLUDED to 1 if you include this project from another
# cmake project (this is handy in combination with git submodules :)
if (NOT BASE64_INCLUDED)
option(BASE64_INSTALL_TARGET "add an install target" ON)
option(BASE64_BUILD_TESTS "add test projects" OFF)

include(TargetSIMDInstructionSet)
option(BASE64_WITH_SSSE3 "add SSSE3 codepath" OFF)
option(BASE64_WITH_AVX2 "add AVX2 codepath" OFF)

#list(APPEND BASE64_NEON_OPTIONS NEON32)
#list(APPEND BASE64_NEON_OPTIONS NEON32-DEFAULTED)
#list(APPEND BASE64_NEON_OPTIONS NEON64)
#if (BASE64_NEON_OPTIONS)
#set(BASE64_WITH_NEON "none" CACHE STRING "which NEON codepath should be choosen")
# list(APPEND BASE64_NEON_OPTIONS none)
# set_property(CACHE BASE64_WITH_NEON PROPERTY STRINGS ${BASE64_NEON_OPTIONS})
# if (NOT ";${BASE64_WITH_NEON};" MATCHES ";${BASE64_NEON_OPTIONS};")
# message(FATAL_ERROR "invalid neon option selected ${BASE64_WITH_NEON}")
#endif()

###################################################################
# OpenMP
find_package(OpenMP)
if (OPENMP_FOUND)
option(BASE64_USE_OpenMP "Utilize OpenMP to parallelize encoding and decoding.")
endif()

####################################################################
# platform/compiler specific configuration
if(MSVC)
# Force to always compile with W4
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
if(${CMAKE_C_FLAGS} MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
endif()
endif()
if (BASE64_GNU_C_COMPATIBLE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Wpedantic")
option(BASE64_INSTALL_TARGET "add an install target" ON)
option(BASE64_BUILD_TESTS "add test projects" OFF)

if (_TARGET_ARCH STREQUAL "x86" OR _TARGET_ARCH STREQUAL "x64")
option(BASE64_WITH_SSSE3 "add SSSE 3 codepath" ON)
option(BASE64_WITH_SSE41 "add SSE 4.1 codepath" ON)
option(BASE64_WITH_SSE42 "add SSE 4.2 codepath" ON)
option(BASE64_WITH_AVX "add AVX codepath" ON)
option(BASE64_WITH_AVX2 "add AVX 2 codepath" ON)

elseif (_TARGET_ARCH STREQUAL "arm")
option(BASE64_WITH_NEON32 "add NEON32 codepath" OFF)

elseif (_TARGET_ARCH STREQUAL "arm64")
option(BASE64_WITH_NEON64 "add NEON64 codepath" ON)

endif()


###################################################################
# OpenMP
find_package(OpenMP)
if (OPENMP_FOUND)
option(BASE64_USE_OpenMP "Utilize OpenMP to parallelize encoding and decoding." ON)
endif()


####################################################################
# platform/compiler specific configuration
if(MSVC)
# Force to always compile with W4
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
if(${CMAKE_C_FLAGS} MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
endif()
endif()
if (BASE64_GNU_C_COMPATIBLE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Wpedantic")
set(CMAKE_LINKER_FLAGS "${CMAKE_LINKER_FLAGS} -r")
endif()


########################################################################
# library project
add_library(base64 STATIC
# library files
lib/lib.c
lib/codec_avx2.c
lib/codec_choose.c
lib/codec_neon32.c
lib/codec_neon64.c
lib/codec_plain.c
lib/codec_ssse3.c

include/libbase64.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
)

########################################################################
# SIMD settings
include(TargetSIMDInstructionSet)
define_SIMD_compile_flags()
if (BASE64_WITH_SSSE3)
set_source_files_properties(lib/codec_ssse3.c PROPERTIES
COMPILE_FLAGS ${COMPILE_FLAGS_SSSE3}
)
if (MSVC)
# if SSSE3 is available it is always enabled by default,
# but MSVC _never_ defines __SSSE3__
set_source_files_properties(lib/codec_ssse3.c PROPERTIES
COMPILE_DEFINITIONS __SSSE3__
)
endif()
set(HAVE_SSSE3 1)
else()
set(HAVE_SSSE3 0)
endif()
if (BASE64_WITH_AVX2)
set_source_files_properties(lib/codec_avx2.c PROPERTIES
COMPILE_FLAGS ${COMPILE_FLAGS_AVX2}
)
set(HAVE_AVX2 1)
else()
set(HAVE_AVX2 0)
endif()
# this needs much more love...
set(HAVE_NEON32 0)
set(HAVE_NEON64 0)
if (BASE64_WITH_NEON MATCHES NEON32)
if(BASE64_WITH_NEON MATCHES NEON32-DEFAULTED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMPILE_FLAGS_NEON32}")
else()
set_source_files_properties(lib/codec_neon32.c PROPERTIES
COMPILE_FLAGS ${COMPILE_FLAGS_NEON32}

if (_TARGET_ARCH STREQUAL "x86" OR _TARGET_ARCH STREQUAL "x64")
macro(configure_codec _TYPE)
if (BASE64_WITH_${_TYPE})
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()
set(HAVE_NEON32 1)
elseif (BASE64_WITH_NEON STREQUAL NEON64)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COMPILE_FLAGS_NEON64}")
set(HAVE_NEON64 1)
endif()

#elseif (_TARGET_ARCH STREQUAL "arm64" AND BASE64_WITH_NEON64)

endif()

target_compile_definitions(base64
PRIVATE
CMD_DEFINED_CONFIG
HAVE_SSSE3=${HAVE_SSSE3}
HAVE_AVX2=${HAVE_AVX2}
HAVE_NEON32=${HAVE_NEON32}
HAVE_NEON64=${HAVE_NEON64}
HAVE_SSSE3=$<BOOL:${BASE64_WITH_SSSE3}>
HAVE_SSE41=$<BOOL:${BASE64_WITH_SSE41}>
HAVE_SSE42=$<BOOL:${BASE64_WITH_SSE42}>
HAVE_AVX=$<BOOL:${BASE64_WITH_AVX}>
HAVE_AVX2=$<BOOL:${BASE64_WITH_AVX2}>
HAVE_NEON32=$<BOOL:${BASE64_WITH_NEON32}>
HAVE_NEON64=$<BOOL:${BASE64_WITH_NEON64}>
)

########################################################################
Expand Down
28 changes: 25 additions & 3 deletions cmake/Modules/TargetArch.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
# 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/
#
########################################################################

macro(target_architecture OUTPUT_VARIABLE)
message(FATAL_ERROR "the target_architecture macro has not been implemented")
endmacro()
function(detect_target_architecture OUTPUT_VARIABLE)
try_compile(_IGNORED "${CMAKE_CURRENT_BINARY_DIR}"
"${CMAKE_SOURCE_DIR}/cmake/test-arch.c"
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()
74 changes: 11 additions & 63 deletions cmake/Modules/TargetSIMDInstructionSet.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Written in 2016 by Henrik Steffen Gaßmann henrik@gassmann.onl
# 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
Expand All @@ -11,76 +11,24 @@
#
########################################################################

include(TargetArch)
include(CheckSymbolExists)

########################################################################
# 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")
#elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC") <- sorry about that, but old cmake versions think "MSVC" is a variable and must be dereferenced :(

#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:AVX2")
set(COMPILE_FLAGS_AVX2 "/arch:AVX2")
endif()
endmacro(define_SIMD_compile_flags)

########################################################################
# compiler feature detection (incomplete & currently unused)
function(detect_target_SIMD_instruction_set_SSSE3 OUTPUT_VARIABLE)
define_SIMD_compile_flags()

set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${COMPILE_FLAGS_SSSE3}")
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
check_symbol_exists(__SSSE3__ "tmmintrin.h" DTCTN_VALUE)
#elseif(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
elseif(MSVC)
# with msvc one would have to try to compile a program referencing
# all used intrinsics. However I do know for sure that MSVC
# supports SSSE3 since MSVC 14 / VS2008...
if (MSVC_VERSION GREATER 1300)
set(DTCTN_VALUE 1)
else()
set(DTCTN_VALUE 0)
endif()
endif()

if (DTCTN_VALUE)
set(${OUTPUT_VARIABLE} ${${OUTPUT_VARIABLE}} SSSE3-FOUND PARENT_SCOPE)
else()
set(${OUTPUT_VARIABLE} ${${OUTPUT_VARIABLE}} SSSE3-NOTFOUND PARENT_SCOPE)
endif()
endfunction(detect_target_SIMD_instruction_set_SSSE3)

function(detect_target_SIMD_instruction_set_AVX2 OUTPUT_VARIABLE)
define_SIMD_compile_flags()

set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${COMPILE_FLAGS_AVX2}")
check_symbol_exists(__AVX2__ "immintrin.h" DTCTN_VALUE)

if (DTCTN_VALUE)
set(${OUTPUT_VARIABLE} ${${OUTPUT_VARIABLE}} AVX2-FOUND PARENT_SCOPE)
else()
set(${OUTPUT_VARIABLE} ${${OUTPUT_VARIABLE}} AVX2-NOTFOUND PARENT_SCOPE)
endif()
endfunction(detect_target_SIMD_instruction_set_AVX2)

function(detect_target_SIMD_instruction_set_NEON OUTPUT_VARIABLE)

endfunction(detect_target_SIMD_instruction_set_NEON)

function(detect_target_SIMD_instruction_set OUTPUT_VARIABLE)
target_architecture(_TARGET_ARCH)

if (APPLE AND CMAKE_OSX_ARCHITECTURES
OR _TARGET_ARCH STREQUAL "i386"
OR _TARGET_ARCH STREQUAL "x86_64")
detect_target_SIMD_instruction_set_SSSE3(_TEMP_OUTPUT)
detect_target_SIMD_instruction_set_AVX2(_TEMP_OUTPUT)
elseif(_TARGET_ARCH MATCHES arm)
# add neon detection
endif()
set(${OUTPUT_VARIABLE} ${_TEMP_OUTPUT} PARENT_SCOPE)
endfunction(detect_target_SIMD_instruction_set)
35 changes: 35 additions & 0 deletions cmake/test-arch.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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/
//
////////////////////////////////////////////////////////////////////////////////

// ARM 64-Bit
#if defined(__aarch64__)
#error ##arch=arm64##

// ARM 32-Bit
#elif defined(__arm__) \
|| defined(_M_ARM)
#error ##arch=arm##

// x86 64-Bit
#elif defined(__x86_64__) \
|| defined(_M_X64)
#error ##arch=x64##

// x86 32-Bit
#elif defined(__i386__) \
|| defined(_M_X86)
#error ##arch=x86##

#else
#error ##arch=unknown##
#endif

0 comments on commit 0d41483

Please sign in to comment.