198 lines
7.1 KiB
CMake
198 lines
7.1 KiB
CMake
cmake_minimum_required (VERSION 3.13)
|
|
|
|
include(CheckTypeSize)
|
|
|
|
project(
|
|
printf
|
|
LANGUAGES C
|
|
DESCRIPTION "Self-contained C implementation of printf, vprintf, sprintf and related functions"
|
|
HOMEPAGE_URL https://github.com/eyalroz/printf
|
|
VERSION 6.0.0
|
|
)
|
|
|
|
option(BUILD_TESTS "Build test programs for the library" OFF)
|
|
option(BUILD_STATIC_LIBRARY "Build the library as static rather than shared" OFF)
|
|
|
|
# Boolean options which go into config.h
|
|
|
|
option(SUPPORT_DECIMAL_SPECIFIERS "Support decimal notation floating-point conversion specifiers (%f,%F)" ON)
|
|
option(SUPPORT_EXPONENTIAL_SPECIFIERS "Support exponential floating point format conversion specifiers (%e,%E,%g,%G)" ON)
|
|
option(SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS "Support the I + bit size integer specifiers (%I8, %I16, %I32, %I64) as in Microsoft Visual C++" ON)
|
|
option(SUPPORT_WRITEBACK_SPECIFIER "Support the length write-back specifier (%n)" ON)
|
|
option(SUPPORT_LONG_LONG "Support long long integral types (allows for the ll length modifier and affects %p)" ON)
|
|
option(CHECK_FOR_NUL_IN_FORMAT_SPECIFIER "Be defensive in the undefined-behavior case of a format specifier not ending before the string ends" ON)
|
|
|
|
set(ALIASING_MODES NONE HARD SOFT)
|
|
set(ALIAS_STANDARD_FUNCTION_NAMES NONE CACHE STRING "Alias the standard library function names (printf, sprintf etc.) to the library's functions - concretely, via a macro, or not at all")
|
|
set_property(CACHE ALIAS_STANDARD_FUNCTION_NAMES PROPERTY STRINGS ${ALIASING_MODES})
|
|
|
|
#option(ALIAS_STANDARD_FUNCTION_NAMES "Alias the standard library function names (printf, sprintf etc.) to the library's functions" ON)
|
|
|
|
if (NOT ${ALIAS_STANDARD_FUNCTION_NAMES} STREQUAL NONE)
|
|
set("ALIAS_STANDARD_FUNCTION_NAMES_${ALIAS_STANDARD_FUNCTION_NAMES}" 1)
|
|
endif()
|
|
|
|
foreach(opt
|
|
SUPPORT_DECIMAL_SPECIFIERS
|
|
SUPPORT_EXPONENTIAL_SPECIFIERS
|
|
SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
|
|
SUPPORT_WRITEBACK_SPECIFIER
|
|
SUPPORT_LONG_LONG
|
|
ALIAS_STANDARD_FUNCTION_NAMES_SOFT
|
|
ALIAS_STANDARD_FUNCTION_NAMES_HARD
|
|
CHECK_FOR_NUL_IN_FORMAT_SPECIFIER
|
|
)
|
|
if (${${opt}})
|
|
set("PRINTF_${opt}" 1)
|
|
else()
|
|
set("PRINTF_${opt}" 0)
|
|
endif()
|
|
endforeach()
|
|
|
|
# Numeric defines which go into printf_config.h
|
|
|
|
set(PRINTF_INTEGER_BUFFER_SIZE "32" CACHE STRING "Integer to string conversion buffer size")
|
|
set(PRINTF_DECIMAL_BUFFER_SIZE "32" CACHE STRING "Floating-point to decimal conversion buffer size")
|
|
set(DEFAULT_FLOAT_PRECISION "6" CACHE STRING "Default precision when printing floating-point values")
|
|
set(MAX_INTEGRAL_DIGITS_FOR_DECIMAL "9" CACHE STRING "Maximum number of integral-part digits of a floating-point value for which printing with %f uses decimal (non-exponential) notation")
|
|
set(LOG10_TAYLOR_TERMS "4" CACHE STRING "The number of terms in a Taylor series expansion of log_10(x) to use for approximation")
|
|
|
|
# Checks related to the 'j', 'z' and 't' size modifiers
|
|
|
|
check_type_size( "long" SIZEOF_LONG )
|
|
check_type_size( "long long" SIZEOF_LONG_LONG )
|
|
|
|
set(ACCEPTABLE_JZT_TYPE_SIZES ${SIZEOF_LONG} ${SIZEOF_LONG_LONG})
|
|
|
|
function(validate_type_size type_name)
|
|
check_type_size(${type_name} TYPE_SIZE)
|
|
if (NOT ${TYPE_SIZE} IN_LIST ACCEPTABLE_JZT_TYPE_SIZES)
|
|
message(FATAL_ERROR "sizeof(${type_name}) is ${TYPE_SIZE}, which is neither sizeof(long) (${SIZEOF_LONG}) nor sizeof(long long) (${SIZEOF_LONG_LONG}). Please contact the library maintainers with your platform details.")
|
|
endif()
|
|
endfunction()
|
|
validate_type_size("intmax_t")
|
|
validate_type_size("size_t")
|
|
validate_type_size("ptrdiff_t")
|
|
|
|
if (BUILD_STATIC_LIBRARY)
|
|
add_library(printf STATIC)
|
|
else()
|
|
add_library(printf SHARED)
|
|
endif()
|
|
|
|
add_library("printf::printf" ALIAS printf)
|
|
|
|
|
|
set(GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")
|
|
configure_file("printf_config.h.in" "${GENERATED_INCLUDE_DIR}/printf_config.h" @ONLY)
|
|
target_sources(printf PRIVATE src/printf/printf.c "${GENERATED_INCLUDE_DIR}/printf_config.h" src/printf/printf.h)
|
|
target_compile_definitions(printf PRIVATE PRINTF_INCLUDE_CONFIG_H)
|
|
target_include_directories(printf PRIVATE "$<BUILD_INTERFACE:${GENERATED_INCLUDE_DIR}>")
|
|
|
|
set_property(TARGET printf PROPERTY C_STANDARD 99)
|
|
set_property(TARGET printf PROPERTY C_STANDARD_REQUIRED ON)
|
|
set_property(TARGET printf PROPERTY C_EXTENSIONS OFF)
|
|
|
|
target_include_directories(
|
|
printf
|
|
PRIVATE
|
|
src
|
|
PUBLIC
|
|
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/src/>"
|
|
)
|
|
|
|
set_target_properties(printf PROPERTIES
|
|
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
|
|
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
|
|
|
|
if (CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
|
target_compile_options(printf PRIVATE /W4)
|
|
elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR
|
|
CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
|
target_compile_options(printf PRIVATE -Wall -Wextra -pedantic -Wconversion)
|
|
if (ALIAS_STANDARD_FUNCTION_NAMES)
|
|
# This is important for preventing our aliased implementation
|
|
# from being replaced, e.g. printf("%c", 'a') by putchar('a');
|
|
# clang and GCC apparently do this as an optimization
|
|
target_compile_options(printf PUBLIC -fno-builtin-printf)
|
|
endif()
|
|
endif()
|
|
|
|
if (BUILD_TESTS)
|
|
enable_testing()
|
|
add_subdirectory(test)
|
|
endif()
|
|
|
|
if (UNIX)
|
|
add_custom_target(printf-sizes
|
|
COMMAND size -A -t $<TARGET_FILE:printf> > printf_sizes.txt
|
|
DEPENDS printf
|
|
BYPRODUCTS printf_sizes.txt
|
|
COMMENT Prints the sizes of the different sections of the ELF file: text, dat, vss etc.)
|
|
|
|
add_custom_target(printf-symbols
|
|
COMMAND nm --numeric-sort --print-size "$<TARGET_FILE:printf>" > printf_symbols.txt
|
|
COMMAND bash -c "nm --numeric-sort --print-size $<TARGET_FILE:printf> | c++filt > printf_cpp_symbols.txt"
|
|
VERBATIM
|
|
DEPENDS printf
|
|
BYPRODUCTS printf_symbols.txt printf_cpp_symbols.txt
|
|
COMMENT Produces lists of the symbols, and C++demangled symbols, inside the library)
|
|
|
|
add_custom_target(printf-lst
|
|
COMMAND objdump --disassemble --line-numbers -S "$<TARGET_FILE:printf>" > printf.list
|
|
DEPENDS printf
|
|
BYPRODUCTS printf.lst
|
|
COMMENT Dissassembles the compiled library into an .lst file)
|
|
|
|
endif()
|
|
|
|
# -------------------------
|
|
# Installation
|
|
# -------------------------
|
|
|
|
include(GNUInstallDirs)
|
|
|
|
# Note: No need for a config.cmake file for setting dependencies - as there
|
|
# are no dependencies; this library is self-contained
|
|
|
|
install(
|
|
TARGETS printf
|
|
EXPORT printf_export
|
|
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
|
|
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
|
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
|
INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
|
|
)
|
|
|
|
install(
|
|
FILES "src/printf/printf.h"
|
|
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/printf"
|
|
)
|
|
|
|
export(
|
|
EXPORT printf_export
|
|
NAMESPACE "printf::"
|
|
FILE "${PROJECT_BINARY_DIR}/printf-targets.cmake"
|
|
)
|
|
|
|
install(
|
|
EXPORT printf_export
|
|
FILE "printf-targets.cmake"
|
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/printf"
|
|
NAMESPACE "printf::"
|
|
)
|
|
|
|
include(CMakePackageConfigHelpers)
|
|
|
|
write_basic_package_version_file(
|
|
"printf-config-version.cmake"
|
|
VERSION ${PROJECT_VERSION}
|
|
COMPATIBILITY SameMinorVersion
|
|
)
|
|
|
|
install(
|
|
FILES "${CMAKE_CURRENT_BINARY_DIR}/printf-config-version.cmake"
|
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/printf"
|
|
)
|