Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
165 changes: 64 additions & 101 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,17 @@ project("str_view"
DESCRIPTION "Robust read-only string handling, tokenization, and matching in C."
)

include_directories("${PROJECT_SOURCE_DIR}/${PROJECT_NAME}")
add_subdirectory("${PROJECT_SOURCE_DIR}/${PROJECT_NAME}")

# For the sake of vcpkg we will make sure cloning and building from
# main will only build the minimal files in the all target. I can't
# protect vcpkg from needlessly downloading
if (EXISTS "${PROJECT_SOURCE_DIR}/samples")
add_subdirectory("${PROJECT_SOURCE_DIR}/samples" EXCLUDE_FROM_ALL)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/samples")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/samples" EXCLUDE_FROM_ALL)
endif()
if (EXISTS "${PROJECT_SOURCE_DIR}/tests")
add_subdirectory("${PROJECT_SOURCE_DIR}/tests" EXCLUDE_FROM_ALL)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests")
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/tests" EXCLUDE_FROM_ALL)
endif()
if (EXISTS "${PROJECT_SOURCE_DIR}/tests" AND EXISTS "${PROJECT_SOURCE_DIR}/samples")
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/samples")
include(tools/scanners.cmake)
endif()

Expand All @@ -38,102 +36,67 @@ else()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
endif()

###############################################################################
################### SV Library Target For Consumers #########################
# Even though we have directories for tests, samples, and utilities, these will
# all be stripped out of releases. So we treat this project as if it's sole
# purpose is to distribute only the core str_view::str_view target and create the library
# target at the root with relative pathing such that the project will compile
# on a user's system regardless of being fetched via FetchContent or
# find_package. This way they also get to include our headers with the str_view
# prefix, such as `#include "str_view/flat_buffer.h"`. Other directories will be
# conditionally detected.
###############################################################################
add_library(${PROJECT_NAME})
add_library(${namespace}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_sources(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/source/${PROJECT_NAME}.c
PUBLIC
FILE_SET public_headers
TYPE HEADERS
BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}
FILES
str_view/${PROJECT_NAME}.h
str_view/configuration.h
)
target_compile_features(${PROJECT_NAME} PUBLIC c_std_11)
if (BUILD_SHARED_LIBS AND WIN32)
target_compile_definitions(${PROJECT_NAME} PUBLIC SV_BUILD_DLL=1)
endif()
# set properties for the target. VERSION set the library version to the project
# version * SOVERSION set the compatibility version for the library to the
# major number of the version
# note that ${public_headers} should be in quotes
set_target_properties(${PROJECT_NAME}
PROPERTIES
RELEASE_POSTFIX "_release"
DEBUG_POSTFIX "_debug"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
C_VISIBILITY_PRESET "default"
VISIBILITY_INLINES_HIDDEN TRUE
)

include(GenerateExportHeader)
generate_export_header(${PROJECT_NAME}
EXPORT_FILE_NAME export/export_${PROJECT_NAME}.h
)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/export>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
set(SV_USER_CONFIGURATION "" CACHE STRING "Freestanding environment with user defined configuration providing necessary functions")
if (SV_USER_CONFIGURATION)
target_compile_definitions(${PROJECT_NAME}
PUBLIC
SV_USER_CONFIGURATION_HEADER="${SV_USER_CONFIGURATION}"
)
endif()
include (cmake/Coverage.cmake)
# where to find our CMake modules
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
#message(STATUS "CMake module path: ${CMAKE_MODULE_PATH}")
include(Installing)

set(SV_COVERAGE_TOOL "" CACHE STRING "Code coverage tool to use for coverage report")
# Code coverage is easy on gcc but clang requires some extra steps. We can
# indicate via our presets that we are using a code coverage preset and we can
# also manually specify the code coverage tool if we have one installed. This
# is helpful for gcc, for example, because I have a newer gcov I like to use
# for the gcc-XX.X compiler; this is not the default one installed.
if (SV_ENABLE_COVERAGE)

if (SV_COVERAGE_TOOL)
set(COVERAGE_TOOL ${SV_COVERAGE_TOOL})
message(STATUS "Using code coverage tool: ${SV_COVERAGE_TOOL}")
endif()

# Clang had very tricky behavior especially on mac to successfully generate
# lcov compatible reports. The command line would not accept clang's
# provided 'llvm-cov gcov' string so a custom script that executes that
# command needs to be generated. We will just place it in the build files.
if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
if (COVERAGE_TOOL)
set(LLVM_COV_EXECUTABLE ${COVERAGE_TOOL})
else()
find_program(LLVM_COV_EXECUTABLE llvm-cov)
if (NOT LLVM_COV_EXECUTABLE)
message(FATAL_ERROR "llvm-cov not found")
endif()
endif()

set(LLVM_GCOV_WRAPPER "${CMAKE_BINARY_DIR}/llvm-gcov")

file(WRITE ${LLVM_GCOV_WRAPPER}
"#!/usr/bin/env bash
exec \"${LLVM_COV_EXECUTABLE}\" gcov \"$@\"
")

file(CHMOD ${LLVM_GCOV_WRAPPER}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)

set(COVERAGE_TOOL ${LLVM_GCOV_WRAPPER})
endif()

if (NOT COVERAGE_TOOL)
message(FATAL_ERROR "no code coverage tool selected")
endif()

# Developer coverage reports include all test files to confirm which test
# cod is ran. This should be for the local developer machine.
add_custom_target(coverage-developer
COMMAND lcov --ignore-errors inconsistent
--gcov-tool ${COVERAGE_TOOL}
--capture
--directory ${CMAKE_BINARY_DIR}
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND lcov --ignore-errors inconsistent
--extract ${CMAKE_SOURCE_DIR}/docs/coverage.info
'${CMAKE_SOURCE_DIR}/tests/*'
'${CMAKE_SOURCE_DIR}/source/*'
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND lcov --remove ${CMAKE_SOURCE_DIR}/docs/coverage.info
'${CMAKE_SOURCE_DIR}/tests/run_tests.c'
-o ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND genhtml ${CMAKE_SOURCE_DIR}/docs/coverage.info
--output-directory ${CMAKE_SOURCE_DIR}/docs/coverage
--prefix ${CMAKE_SOURCE_DIR}
--title "SV Test Suite Coverage Report"
)

# The published report on github pages should not include tests as I don't
# want the C Container Collection to be seen as including tests to inflate
# coverage numbers. We want to build trust and show we are working hard on
# good library not just padding imaginary numbers.
add_custom_target(coverage-publish
COMMAND lcov --ignore-errors inconsistent
--gcov-tool ${COVERAGE_TOOL}
--capture
--directory ${CMAKE_BINARY_DIR}
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND lcov --ignore-errors inconsistent
--extract ${CMAKE_SOURCE_DIR}/docs/coverage.info
'${CMAKE_SOURCE_DIR}/source/*'
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND genhtml ${CMAKE_SOURCE_DIR}/docs/coverage.info
--output-directory ${CMAKE_SOURCE_DIR}/docs/coverage
--prefix ${CMAKE_SOURCE_DIR}
--flat
--title "SV Test Suite Coverage Report"
)
endif()
77 changes: 75 additions & 2 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ To avoid including tests, samples, and other extraneous files when fetching cont
```cmake
include(FetchContent)
FetchContent_Declare(
ccc
str_view
URL https://github.com/skeletoss/str_view/releases/download/v[MAJOR.MINOR.PATCH]/str_view-v[MAJOR.MINOR.PATCH].zip
#DOWNLOAD_EXTRACT_TIMESTAMP FALSE # CMake may raise a warning to set this. If so, uncomment and set.
URL_HASH SHA256=[HASH]
SYSTEM # Optional flag to mark ccc as a system library and silence compiler and tooling warnings.
)
FetchContent_MakeAvailable(str_view)
# Optionally ignore compiler warnings from the str_view library.
Expand All @@ -31,10 +32,11 @@ Here is a concrete example with an arbitrary release that is likely out of date.
```cmake
include(FetchContent)
FetchContent_Declare(
ccc
str_view
URL https://github.com/skeletoss/str_view/releases/download/v0.7.2/str_view-v0.7.2.zip
#DOWNLOAD_EXTRACT_TIMESTAMP FALSE # CMake may raise a warning to set this. If so, uncomment and set.
URL_HASH SHA256=cbe9aa4f416ea13502cd48d089e5cb67d7f3552772b0a88773f62a9fe4cf1a5a
SYSTEM # Optional flag to mark ccc as a system library and silence compiler and tooling warnings.
)
FetchContent_MakeAvailable(str_view)
# Optionally ignore compiler warnings from the str_view library.
Expand All @@ -48,6 +50,77 @@ target_link_libraries(main str_view::str_view)

Now, `str_view` is part of your project build, allowing you to configure as you see fit. For a more traditional approach read the manual install section below.

## Freestanding Environments

The string view library uses the following functions or macros that must be supported by the user on freestanding targets.

Traditionally included via `<string.h>`:

- `memmove()`
- `memcmp()`
- `strlen()`
- `strnlen()`

To provide these functions, the user may create a header. For example, `my_sv_configuration.h`.

```txt
my_project/
my_sv_configuration/
my_sv_configuration.h
```

In this header the user has two options: provide the listed functions directly or include their versions of the headers that provide the needed functionality. It is common for freestanding environments to provide their own `<string.h>` that implement these functions.

```c
#ifndef MY_SV_CONFIGURATION_H
#define MY_SV_CONFIGURATION_H
#include "lib/string.h" /* IWYU pragma: export */
#endif /* MY_SV_CONFIGURATION_H */
```

The Include What You Use (IWYU) comment is helpful if you want to avoid tooling warnings in SV code and have not marked SV code as a system library to silence such warnings. If you are providing functions directly, this is not applicable. Then, ensure the string view library can find that header.

```cmake
include(FetchContent)
FetchContent_Declare(
str_view
URL https://github.com/skeletoss/str_view/releases/download/v0.7.2/str_view-v0.7.2.zip
#DOWNLOAD_EXTRACT_TIMESTAMP FALSE # CMake may raise a warning to set this. If so, uncomment and set.
URL_HASH SHA256=cbe9aa4f416ea13502cd48d089e5cb67d7f3552772b0a88773f62a9fe4cf1a5a
SYSTEM # Optional flag to mark ccc as a system library and silence compiler and tooling warnings.
)
FetchContent_MakeAvailable(str_view)
# Include this line if you want to ignore compiler warnings from the ccc library when compiling your project.
target_compile_options(ccc PRIVATE "-w")

# New step allowing CCC to find the configuration header.
target_include_directories(str_view PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/my_sv_configuration>
)

add_executable(freestanding freestanding.c)
target_link_libraries(freestanding str_view::str_view)
```

Now pass the flag to CMake at configure time via `CMakePresets.json`, `CMakeUserPresets.json`, or the command line.

```json
"cacheVariables": {
"SV_USER_CONFIGURATION": "my_sv_configuration.h",
}
```

Or they can be passed on the command line.

```zsh
cmake --preset=my-preset\
-DSV_USER_CONFIGURATION="my_sv_configuration.h"\
```

Now the library is fully configured to be built as part of the user project in a freestanding environment.

Any other C headers that the collection uses internally, such as `<stdint.h>` and `<stddef.h>`, are those provided by the C standard on freestanding targets and do not require a user implementation.

## Manual Install Quick Start

1. Use the provided defaults
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Read the [DOCS](https://skeletoss.github.io/str_view/).

## Install Instructions

This library offers a manual installation through the [Releases](https://github.com/skeletoss/str_view/releases) page or fetch content install via CMake.
This library offers a manual installation through the [Releases](https://github.com/skeletoss/str_view/releases) page or fetch content install via CMake. Freestanding environments are supported!

See [INSTALL.md](/INSTALL.md) file for instructions on how to install the `str-view` port through vcpkg or how to manually download, build, and install the library.

Expand Down
94 changes: 94 additions & 0 deletions cmake/Coverage.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
set(SV_COVERAGE_TOOL "" CACHE STRING "Code coverage tool to use for coverage report")
# Code coverage is easy on gcc but clang requires some extra steps. We can
# indicate via our presets that we are using a code coverage preset and we can
# also manually specify the code coverage tool if we have one installed. This
# is helpful for gcc, for example, because I have a newer gcov I like to use
# for the gcc-XX.X compiler; this is not the default one installed.
if (SV_ENABLE_COVERAGE)

if (SV_COVERAGE_TOOL)
set(COVERAGE_TOOL ${SV_COVERAGE_TOOL})
message(STATUS "Using code coverage tool: ${SV_COVERAGE_TOOL}")
endif()

# Clang had very tricky behavior especially on mac to successfully generate
# lcov compatible reports. The command line would not accept clang's
# provided 'llvm-cov gcov' string so a custom script that executes that
# command needs to be generated. We will just place it in the build files.
if (CMAKE_C_COMPILER_ID STREQUAL "Clang")
if (COVERAGE_TOOL)
set(LLVM_COV_EXECUTABLE ${COVERAGE_TOOL})
else()
find_program(LLVM_COV_EXECUTABLE llvm-cov)
if (NOT LLVM_COV_EXECUTABLE)
message(FATAL_ERROR "llvm-cov not found")
endif()
endif()

set(LLVM_GCOV_WRAPPER "${CMAKE_BINARY_DIR}/llvm-gcov")

file(WRITE ${LLVM_GCOV_WRAPPER}
"#!/usr/bin/env bash
exec \"${LLVM_COV_EXECUTABLE}\" gcov \"$@\"
")

file(CHMOD ${LLVM_GCOV_WRAPPER}
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE)

set(COVERAGE_TOOL ${LLVM_GCOV_WRAPPER})
endif()

if (NOT COVERAGE_TOOL)
message(FATAL_ERROR "no code coverage tool selected")
endif()

# Developer coverage reports include all test files to confirm which test
# cod is ran. This should be for the local developer machine.
add_custom_target(coverage-developer
COMMAND lcov --ignore-errors inconsistent
--gcov-tool ${COVERAGE_TOOL}
--capture
--directory ${CMAKE_BINARY_DIR}
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND lcov --ignore-errors inconsistent
--extract ${CMAKE_SOURCE_DIR}/docs/coverage.info
'${CMAKE_SOURCE_DIR}/tests/*'
'${CMAKE_SOURCE_DIR}/source/*'
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND lcov --remove ${CMAKE_SOURCE_DIR}/docs/coverage.info
'${CMAKE_SOURCE_DIR}/tests/run_tests.c'
-o ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND genhtml ${CMAKE_SOURCE_DIR}/docs/coverage.info
--output-directory ${CMAKE_SOURCE_DIR}/docs/coverage
--prefix ${CMAKE_SOURCE_DIR}
--title "SV Test Suite Coverage Report"
)

# The published report on github pages should not include tests as I don't
# want the C Container Collection to be seen as including tests to inflate
# coverage numbers. We want to build trust and show we are working hard on
# good library not just padding imaginary numbers.
add_custom_target(coverage-publish
COMMAND lcov --ignore-errors inconsistent
--gcov-tool ${COVERAGE_TOOL}
--capture
--directory ${CMAKE_BINARY_DIR}
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND lcov --ignore-errors inconsistent
--extract ${CMAKE_SOURCE_DIR}/docs/coverage.info
'${CMAKE_SOURCE_DIR}/source/*'
--output-file ${CMAKE_SOURCE_DIR}/docs/coverage.info

COMMAND genhtml ${CMAKE_SOURCE_DIR}/docs/coverage.info
--output-directory ${CMAKE_SOURCE_DIR}/docs/coverage
--prefix ${CMAKE_SOURCE_DIR}
--flat
--title "SV Test Suite Coverage Report"
)
endif()
Loading
Loading