Commit dfe6d938 authored by Michael Tesch's avatar Michael Tesch
Browse files

Ch fix func impls round

parent 778f92d5
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ cover:
  stage: cover
  script:
  - dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
  - cmake -Bbuild-cov -H. -DCPPDUALS_TESTING=ON -DCODE_COVERAGE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
  - cmake -Bbuild-cov -H. -DCPPDUALS_TESTING=ON -DCPPDUALS_CODE_COVERAGE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
  - cmake --build build-cov --target cov
  - cmake --build build-cov --target cov-html
  coverage: "/Total:|\\w*\\d+\\.\\d+/"
@@ -58,10 +58,10 @@ pages:
  script:
  - dnf install -y gcc-c++ make cmake git doxygen lcov graphviz
  - cmake -Bbuild-cov -H. -DCODE_COVERAGE=ON -DCPPDUALS_TESTING=ON
  - cmake --build build-cov --target cppduals_docs
  - cmake --build build-cov --target cov-html
  - mv build-cov/docs public/
  - cmake --build build-cov --target cppduals_docs
  - mv build-cov/coverage public/
  - mv build-cov/docs public/
  coverage: "/Total:|\\w*\\d+\\.\\d+/"
  artifacts:
    paths:
+19 −19
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@
#
cmake_minimum_required (VERSION 3.14)
project (cppduals
  VERSION 0.6.0
  VERSION 0.6.1
  LANGUAGES C CXX
  )
include (GNUInstallDirs)
@@ -46,7 +46,6 @@ set_property (CACHE CMAKE_CXX_STANDARD PROPERTY STRINGS 20)

option (CPPDUALS_TESTING "Enable testing" OFF)
option (CPPDUALS_BENCHMARK "Enable benchmarking" OFF)
option (CPPDUALS_EIGEN_LATEST "Eigen latest" OFF)
option (CPPDUALS_USE_LIBCXX "When testing use flags for libc++" OFF)
set (EIGEN3_INCLUDE_DIRS "" CACHE PATH "Path to Eigen includes" )

@@ -113,7 +112,6 @@ if (CPPDUALS_TESTING)
                             "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}"
                             "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
                             "-DCPPDUALS_BENCHMARK=${CPPDUALS_BENCHMARK}"
                             "-DCPPDUALS_EIGEN_LATEST=${CPPDUALS_EIGEN_LATEST}"
                             "-DCPPDUALS_USE_LIBCXX=${CPPDUALS_USE_LIBCXX}"
                             "${PROJECT_SOURCE_DIR}/thirdparty"
    RESULT_VARIABLE DEPS_CONFIG_RESULT
@@ -148,8 +146,12 @@ endif ()
# Code Coverage Configuration
#
add_library (cppduals_coverage_config INTERFACE)
option (CODE_COVERAGE "Enable coverage reporting" OFF)
if (CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
option (CPPDUALS_CODE_COVERAGE "Enable coverage reporting" OFF)
if (CPPDUALS_CODE_COVERAGE AND NOT CPPDUALS_TESTING)
  message(FATAL_ERROR "CPPDUALS_CODE_COVERAGE requires CPPDUALS_TESTING to be enabled")
endif()
if (CPPDUALS_CODE_COVERAGE)
  if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    message(STATUS "Enabling coverage reporting")
    # Add required flags (GCC & LLVM/Clang)
    target_compile_options (cppduals_coverage_config INTERFACE
@@ -159,14 +161,12 @@ if (CODE_COVERAGE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
      -fprofile-arcs 
      -ftest-coverage
    )
  if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
    target_link_options (cppduals_coverage_config INTERFACE 
      --coverage
    )
  else()
    target_link_options (cppduals_coverage_config INTERFACE 
      --coverage
    )
    # error out if coverage is enabled but compiler is not supported
    message(FATAL_ERROR "Coverage reporting is disabled for unknown compilers.")
  endif ()
endif ()

+15 −49
Original line number Diff line number Diff line
SHELL=bash
TARGET=cppduals
CMAKE_OPTIONS=-DCPPDUALS_TESTING=ON -DCPPDUALS_BENCHMARK=ON -DCPPDUALS_EIGEN_LATEST=OFF
CMAKE_OPTIONS=-DCPPDUALS_TESTING=ON -DCPPDUALS_BENCHMARK=ON
CMAKE=cmake
DEFAULT_TARGET=package
GCC?=gcc-14
@@ -13,24 +13,17 @@ export CMAKE_BUILD_PARALLEL_LEVEL
all:
	[ `uname` != Darwin ] || $(MAKE) clang clangr cc ccr osx osxr ios iosr
	[ `uname` != Linux ]  || $(MAKE) cc ccr
	[ ! -d ~/.android ] || $(MAKE) android
	[ ! -f ~/.emscripten ] || $(MAKE) em

help:
	@echo "Make targets for :" $(TARGET)
	@echo " clang   	    - build debug package using clang compiler"
	@echo " clangr       - build release package using clang compiler"
	@echo " test         - "
	@echo " test-clang   - "
	@echo " cov          - build test coverage report"
	@echo " osx          - build debug package using XCode command-line"
	@echo " osxr         - build release package using XCode command-line"
	@echo " cc           - build debug package using cc/gcc compiler"
	@echo " ccr          - build release package using cc/gcc compiler"
	@echo " and          - build android using gradle in ./Android"
	@echo " em-sdl2      - build debug package using cc/gcc compiler"
	@echo " em           ^ alias"
	@echo " em-sdl2r     - build release package using cc/gcc compiler"
	@echo " emr          ^ alias"
	@echo " "
	@echo " distclean    - remove ALL build directories from the above targets"
#	@echo " tags         - "
@@ -41,13 +34,15 @@ Build-clang/Makefile Build-clang/compile_commands.json:
		-G'Unix Makefiles' \
		$(CMAKE_OPTIONS) \
		-DCMAKE_BUILD_TYPE=Debug \
		-DCMAKE_EXPORT_COMPILE_COMMANDS=1
		-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
		-DCPPDUALS_TESTING=ON \
		-DCPPDUALS_CODE_COVERAGE=ON

Build-clangr/Makefile:
	CC=$(CLANG) CXX=$(CLANGXX) $(CMAKE) . -BBuild-clangr \
		-G'Unix Makefiles' \
		$(CMAKE_OPTIONS) \
		-DCMAKE_BUILD_TYPE=RelWithDebInfo
		-DCMAKE_BUILD_TYPE=RelWithDebInfo \
		-DCMAKE_EXPORT_COMPILE_COMMANDS=1

Build-cc/Makefile:
@@ -56,7 +51,8 @@ Build-cc/Makefile:
		$(CMAKE_OPTIONS) \
		-DCMAKE_BUILD_TYPE=Debug \
		-DCMAKE_EXPORT_COMPILE_COMMANDS=1 \
		-DCPPDUALS_TESTING=ON -DCODE_COVERAGE=ON
		-DCPPDUALS_TESTING=ON \
		-DCPPDUALS_CODE_COVERAGE=ON

Build-ccr/Makefile:
	CC=$(GCC) CXX=$(GXX) $(CMAKE) . -BBuild-ccr \
@@ -85,8 +81,12 @@ test: ccr clangr
	CTEST_OUTPUT_ON_FAILURE=y $(CMAKE) --build Build-clangr --target test

cov: cc
	CMAKE_BUILD_PARALLEL_LEVEL=8 $(CMAKE) --build Build-cc --target test
	$(CMAKE) --build Build-cc --target cov-html
	CMAKE_BUILD_PARALLEL_LEVEL=8 $(CMAKE) --build Build-cc --target cov-html
	echo "coverage report is in Build-cc/coverage/index.html"

cov-clang: clang
	CMAKE_BUILD_PARALLEL_LEVEL=8 $(CMAKE) --build Build-clang --target cov-html
	@echo "coverage report is in Build-clang/coverage/html/index.html"

Build-osx/cppduals.xcodeproj:
	$(CMAKE) . -BBuild-osx -GXcode $(CMAKE_OPTIONS)
@@ -97,42 +97,8 @@ osx: Build-osx/cppduals.xcodeproj
osxr: Build-osx/cppduals.xcodeproj
	$(CMAKE) --build Build-osx --config Release --target $(DEFAULT_TARGET)

Frameworks.iOS/SDL2.framework/SDL2:
	echo "Running ./scripts/Build_SDL2_framework.sh ios"
	./scripts/Build_SDL2_framework.sh ios

and:
	cd Android && ./gradlew build

Build-emsc/Makefile:
	source ${HOME}/local/emsdk/emsdk_env.sh ; \
	emcmake $(CMAKE) . -BBuild-emsc -DBUILD_SDL2=OFF -DBUILD_FREETYPE=OFF \
		$(CMAKE_OPTIONS)
#		-DCMAKE_TOOLCHAIN_FILE=$${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake

Build-emscr/Makefile:
	source ${HOME}/local/emsdk/emsdk_env.sh ; \
	emcmake $(CMAKE) . -BBuild-emscr -DBUILD_SDL2=OFF \
		-DBUILD_FREETYPE=OFF $(CMAKE_OPTIONS) -DCMAKE_BUILD_TYPE=Release

em-sdl2: Build-emsc/Makefile
	cd Build-emsc && $(MAKE) cppduals

em-sdl2r: Build-emscr/Makefile
	cd Build-emscr && $(MAKE) cppduals

em-glfw: Build-emscgl/Makefile
	cd Build-emscgl && $(MAKE) cppduals

em: em-sdl2

emrun: em-sdl2
	source ${HOME}/local/emsdk/emsdk_env.sh && cd Build-emsc/ && emrun --serve_after_close cppduals.html

emr: em-sdl2r

distclean:
	rm -rf Build-* Android/app/.cxx/
	rm -rf Build-*

tags:
	cd Build-ccr && $(MAKE) tags
+23 −25
Original line number Diff line number Diff line
@@ -578,7 +578,7 @@ public:
    : _real(x.rpart()), _dual(x.dpart()) {}

  /// Cast to a complex<dual<>> with real part equal to *this.
  operator std::complex<dual<T>>() { return std::complex<dual<T>>(*this); }
  operator std::complex<dual<T>>() { return std::complex<dual<T>>(*this, (T)0); }

  /// Explicit cast to an arithmetic type retains the rpart()
  template <class X,
@@ -850,7 +850,7 @@ namespace detail {
  template<class T> dual<T> fmin_impl(const dual<T> & x, const dual<T> & y);
  template<class T> dual<T> frexp_impl(const dual<T> & x, int* exp);
  template<class T> dual<T> ldexp_impl(const dual<T> & x, int exp);
  template<class T> T trunc_impl(const dual<T> & x);
  template<class T> dual<T> trunc_impl(const dual<T> & x);
  template<class T> dual<T> floor_impl(const dual<T> & x);
  template<class T> dual<T> ceil_impl(const dual<T> & x);
  template<class T> dual<T> round_impl(const dual<T> & x);
@@ -920,7 +920,7 @@ template<class T> dual<T> fmin(const dual<T> & x, const dual<T> & y) { return de
template<class T> dual<T> frexp(const dual<T> & x, int* exp) { return detail::frexp_impl(x, exp); }
template<class T> dual<T> ldexp(const dual<T> & x, int exp) { return detail::ldexp_impl(x, exp); }
//template<class T> dual<T> trunc(const dual<T> & x) { return detail::trunc_impl(x); }
template<class T> T trunc(const dual<T> & x) { return detail::trunc_impl(x); }
template<class T> dual<T> trunc(const dual<T> & x) { return detail::trunc_impl(x); }
template<class T> dual<T> floor(const dual<T> & x) { return detail::floor_impl(x); }
template<class T> dual<T> ceil(const dual<T> & x) { return detail::ceil_impl(x); }
template<class T> dual<T> round(const dual<T> & x) { return detail::round_impl(x); }
@@ -933,8 +933,8 @@ template<class T> bool isnan(const dual<T> & x) { return detail::isnan_impl(x);
template<class T> bool signbit(const dual<T> & x) { return detail::signbit_impl(x); }
template<class T> dual<T> copysign(const dual<T> & x, const dual<T> & y) { return detail::copysign_impl(x, y); }

template<class T> dual<T> random(const dual<T> & low, const dual<T> & high) { return detail::random_impl(low, high); }
template<class T> dual<T> random2(const dual<T> & low, const dual<T> & high) { return detail::random2_impl(low, high); }
//template<class T> dual<T> random(const dual<T> & low, const dual<T> & high) { return detail::random_impl(low, high); }
//template<class T> dual<T> random2(const dual<T> & low, const dual<T> & high) { return detail::random2_impl(low, high); }

namespace utils {
template <typename T> int sgn(T val) {
@@ -1129,7 +1129,13 @@ template<class T> dual<T> log2_impl(const dual<T> & x) {
}

template<class T> duals::dual<T> logb_impl(const duals::dual<T> & x) {
  return duals::log2(x);
  using std::log;
  using std::pow;
  using std::abs;
  using std::floor;
  T v = floor(log(abs(x.rpart())) / log(std::numeric_limits<T>::radix));
  return duals::dual<T>(v,
                        x.rpart() - pow(2,v) ? (T)0 : std::numeric_limits<T>::infinity());
}

// dual<T> ^ U implementation
@@ -1440,46 +1446,38 @@ template<class T> dual<T> lgamma_impl(const dual<T> & x) {
    return dual<T>(v, x.dpart() * w);
  }
}

template<class T> dual<T> abs_impl(const dual<T> & x) {
  using std::abs;
  return dual<T>(abs(x.rpart()),
                 x.dpart() * utils::sgn(x.rpart()));
}

template<class T> dual<T> fabs_impl(const dual<T> & x) {
  using std::fabs;
  return dual<T>(fabs(x.rpart()),
                 x.dpart() * utils::sgn(x.rpart()));
}

template<class T> duals::dual<T> fmax_impl(const duals::dual<T> & x, const duals::dual<T> & y) {
  return x.rpart() > y.rpart() ? x : y;
}

template<class T> duals::dual<T> fmin_impl(const duals::dual<T> & x, const duals::dual<T> & y) {
  return x.rpart() <= y.rpart() ? x : y;
}

template<class T> T (frexp_impl)(const duals::dual<T> & arg, int* exp ) { return (frexp)(arg.rpart(), exp); }
template<class T> duals::dual<T> (ldexp_impl)(const duals::dual<T> & arg, int exp ) { return arg * std::pow((T)2,exp); }
template<class T> T trunc_impl(const duals::dual<T> & d) { using std::trunc; return (trunc)(d.rpart()); }

template<class T> duals::dual<T> frexp_impl(const duals::dual<T> & arg, int* exp ) { using std::frexp; return frexp(arg.rpart(), exp); }
template<class T> duals::dual<T> ldexp_impl(const duals::dual<T> & arg, int exp ) { return arg * std::pow((T)2,exp); }
template<class T> duals::dual<T> trunc_impl(const duals::dual<T> & d) { using std::trunc; return trunc(d.rpart()); }
template<class T> dual<T> floor_impl(const dual<T> & x) {
  using std::floor;
  return dual<T>(floor(x.rpart()),
                 x.dpart() * utils::sgn(x.rpart()-floor(x.rpart())));
}
template<class T> duals::dual<T> (ceil_impl)(const duals::dual<T> & d)  { using std::ceil; return (ceil)(d.rpart()); }
template<class T> T (round_impl)(const duals::dual<T> & d) { using std::round; return (round)(d.rpart()); }

template<class T> int fpclassify_impl(const duals::dual<T> & d) { using std::fpclassify; return (fpclassify)(d.rpart()); }
template<class T> bool isfinite_impl(const duals::dual<T> & d) { using std::isfinite; return (isfinite)(d.rpart()); }
template<class T> bool isnormal_impl(const duals::dual<T> & d) { using std::isnormal; return (isnormal)(d.rpart()); }
template<class T> bool isinf_impl(const duals::dual<T> & d) { using std::isinf; return (isinf)(d.rpart()); }
template<class T> bool isnan_impl(const duals::dual<T> & d) { using std::isnan; return (isnan)(d.rpart()); }
template<class T> bool signbit_impl(const duals::dual<T> & d) { using std::signbit; return (signbit)(d.rpart()); }

template<class T> duals::dual<T> ceil_impl(const duals::dual<T> & d)  { using std::ceil; return ceil(d.rpart()); }
template<class T> duals::dual<T> round_impl(const duals::dual<T> & d) { using std::round; return round(d.rpart()); }
template<class T> int fpclassify_impl(const duals::dual<T> & d) { using std::fpclassify; return fpclassify(d.rpart()); }
template<class T> bool isfinite_impl(const duals::dual<T> & d) { using std::isfinite; return isfinite(d.rpart()); }
template<class T> bool isnormal_impl(const duals::dual<T> & d) { using std::isnormal; return isnormal(d.rpart()); }
template<class T> bool isinf_impl(const duals::dual<T> & d) { using std::isinf; return isinf(d.rpart()); }
template<class T> bool isnan_impl(const duals::dual<T> & d) { using std::isnan; return isnan(d.rpart()); }
template<class T> bool signbit_impl(const duals::dual<T> & d) { using std::signbit; return signbit(d.rpart()); }
template<class T> duals::dual<T> copysign_impl(const duals::dual<T> & x, const duals::dual<T> & y) {
  using std::copysign;
  T r = copysign(x.rpart(), y.rpart());
+103 −59
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ else ()
endif ()

# Set optimization flags only if coverage is not enabled
if (NOT CODE_COVERAGE)
if (NOT CPPDUALS_CODE_COVERAGE)
  if (X86)
    if (NOT MSVC)
      set (OPT_FLAGS "-O3;-march=native")
@@ -41,9 +41,17 @@ if (NOT CODE_COVERAGE)
  else ()
    set (OPT_FLAGS "-O3")
  endif ()
else()
  if (X86)
    if (NOT MSVC)
      set (OPT_FLAGS "-mavx2")
    else ()
      set (OPT_FLAGS "/arch:AVX2")
    endif ()
  else ()
    set (OPT_FLAGS "")
  endif ()
endif ()

set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_VECTORIZE_CDUAL")

@@ -86,14 +94,12 @@ foreach (TEST_ ${ALL_TESTS})
endforeach (TEST_)

# special for fmt
target_compile_features (test_fmt_1 PUBLIC cxx_std_14)
target_link_libraries (test_fmt_1 fmt::fmt)

if (CPPDUALS_BENCHMARK)
  #
  # Benchmarks
  #

  if (Boost_FOUND AND NO)
    add_definitions (-DHAVE_BOOST=1)
    include_directories ("${Boost_INCLUDE_DIRS}")
@@ -165,37 +171,34 @@ if (CPPDUALS_BENCHMARK)
      break()
    endif (EXISTS "${CBLAS_INCLUDE_DIRS}/${cblas}")
  endforeach (cblas)
  if (APPLE)
    add_definitions(-DACCELERATE_NEW_LAPACK)
  endif ()
  message ("Found BLAS    : ${BLAS_LIBRARIES}")
  message ("Found cBLAS   : ${CBLAS_INCLUDE_DIRS}")
  message ("Found lapacke : ${LAPACKE_INCLUDE_DIRS}")

  set (OPT_FLAGS "")
  set (BMK_FLAGS "")
  if (NOT MSVC)
    #set (OPT_FLAGS "-O3;-mavx")
    #set (OPT_FLAGS "-O3;-march=native;-fopenmp")
    #set (BMK_FLAGS "-O3;-mavx")
    #set (BMK_FLAGS "-O3;-march=native;-fopenmp")
    if (X86)
      set (OPT_FLAGS "-msse3;-fopenmp")
      set (OPT_FLAGS "-msse3")
      set (OPT_FLAGS "-march=native;-funroll-loops")
      set (OPT_FLAGS "-msse3;-mavx2;-mfma")
      set (BMK_FLAGS "-msse3;-fopenmp")
      set (BMK_FLAGS "-msse3")
      set (BMK_FLAGS "-march=native;-funroll-loops")
      set (BMK_FLAGS "-msse3;-mavx2;-mfma")
    else ()
      set (OPT_FLAGS "-march=native")
      set (BMK_FLAGS "-march=native")
    endif ()
    #set (OPT_FLAGS "-O3;${OPT_FLAGS}")
    #set (OPT_FLAGS "${OPT_FLAGS};-save-temps;-fverbose-asm")
    #set (BMK_FLAGS "-O3;${BMK_FLAGS}")
    #set (BMK_FLAGS "${BMK_FLAGS};-save-temps;-fverbose-asm")
  else ()
    set (OPT_FLAGS "/arch:IA32")
    set (OPT_FLAGS "/arch:SSE")
    set (OPT_FLAGS "/arch:SSE2")
    set (OPT_FLAGS "/arch:AVX2")
    set (BMK_FLAGS "/arch:IA32")
    set (BMK_FLAGS "/arch:SSE")
    set (BMK_FLAGS "/arch:SSE2")
    set (BMK_FLAGS "/arch:AVX2")
  endif ()

  #set (OPT_FLAGS "${OPT_FLAGS};-DEIGEN_DONT_VECTORIZE")
  #set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE")
  #set (OPT_FLAGS "${OPT_FLAGS};-DCPPDUALS_DONT_VECTORIZE_CDUAL")
  #set (BMK_FLAGS "${BMK_FLAGS};-DEIGEN_DONT_VECTORIZE")
  #set (BMK_FLAGS "${BMK_FLAGS};-DCPPDUALS_DONT_VECTORIZE")
  #set (BMK_FLAGS "${BMK_FLAGS};-DCPPDUALS_DONT_VECTORIZE_CDUAL")

  foreach (VECTORIZE YES NO)
    foreach (BENCH  bench_dual bench_eigen bench_exp bench_gemm bench_example bench_fmt)
@@ -205,14 +208,14 @@ if (CPPDUALS_BENCHMARK)
        set (BENCHE ${BENCH}_novec)
      endif ()
      add_executable (${BENCHE} ${BENCH}.cpp)
      target_compile_options (${BENCHE} PUBLIC ${OPT_FLAGS})
      target_compile_options (${BENCHE} PUBLIC ${BMK_FLAGS})
      if (NOT VECTORIZE)
        target_compile_options (${BENCHE} PUBLIC "-DEIGEN_DONT_VECTORIZE")
      endif()
      #set_target_properties (${BENCH} PROPERTIES LINK_FLAGS -fopenmp)
      #target_link_options (${BENCH} PUBLIC ${OPT_FLAGS})
      string (REPLACE ";" ", " L2 "${OPT_FLAGS} ${CMAKE_CXX_FLAGS}")
      target_compile_definitions (${BENCHE} PRIVATE "OPT_FLAGS=${L2}")
      #target_link_options (${BENCH} PUBLIC ${BMK_FLAGS})
      string (REPLACE ";" ", " L2 "${BMK_FLAGS} ${CMAKE_CXX_FLAGS}")
      target_compile_definitions (${BENCHE} PRIVATE "BMK_FLAGS=${L2}")
      target_link_libraries (${BENCHE} benchmark::benchmark ${BLAS_LIBRARIES} eigen expokit)
    endforeach ()
  endforeach ()
@@ -223,7 +226,7 @@ if (CPPDUALS_BENCHMARK)
endif (CPPDUALS_BENCHMARK)

add_executable (sandbox sandbox.cpp)
#target_compile_options (sandbox PUBLIC ${OPT_FLAGS})
#target_compile_options (sandbox PUBLIC ${BMK_FLAGS})
target_compile_options (sandbox PUBLIC -DCPPDUALS_VECTORIZE_CDUAL)
if (MSVC)
  if (X86)
@@ -243,44 +246,84 @@ target_link_libraries (sandbox PUBLIC cppduals_coverage_config eigen expokit)
#
# Generate coverage reports
#
if (CODE_COVERAGE)
if (CPPDUALS_CODE_COVERAGE)
  # Find required tools
  find_program(LLVM_COV_PATH llvm-cov)
  find_program(LLVM_PROFDATA_PATH llvm-profdata)
  find_program(LCOV_PATH lcov)
  find_program(GENHTML_PATH genhtml)
  get_filename_component(CMAKE_CXX_COMPILER_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
  set(GENHTML_PATH ${CMAKE_CXX_COMPILER_DIR}/genhtml)
  if(NOT EXISTS ${GENHTML_PATH})
    find_program(GENHTML_PATH genhtml REQUIRED)
  endif()

  if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    if(LLVM_COV_PATH AND LLVM_PROFDATA_PATH)
    # Clang
    # often in the same directory as clang - search there too
    get_filename_component(CMAKE_CXX_COMPILER_DIR "${CMAKE_CXX_COMPILER}" DIRECTORY)
    set(LLVM_COV_PATH ${CMAKE_CXX_COMPILER_DIR}/llvm-cov)
    set(LLVM_PROFDATA_PATH ${CMAKE_CXX_COMPILER_DIR}/llvm-profdata)
    if(NOT EXISTS ${LLVM_COV_PATH})
      find_program(LLVM_COV_PATH llvm-cov REQUIRED)
    endif()
    if(NOT EXISTS ${LLVM_PROFDATA_PATH})
      find_program(LLVM_PROFDATA_PATH llvm-profdata REQUIRED)
    endif()
    
    add_custom_target(cov
      DEPENDS ${ALL_TEST_BINS}
        COMMAND ${CMAKE_COMMAND} -E make_directory coverage
        COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test
        COMMAND ${LLVM_PROFDATA_PATH} merge -sparse default.profraw -o default.profdata
        COMMAND ${LLVM_COV_PATH} export -format=lcov -instr-profile=default.profdata ${ALL_TEST_BINS} > coverage/coverage.info
        COMMAND ${LCOV_PATH} --remove coverage/coverage.info '/usr/*' --output-file coverage/coverage.info
        COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/thirdparty/*' --output-file coverage/coverage.info 
        COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/googletest/*' --output-file coverage/coverage.info
        COMMAND ${LCOV_PATH} --list coverage/coverage.info
      COMMAND ${CMAKE_COMMAND} -E remove_directory coverage/profraw
      COMMAND ${CMAKE_COMMAND} -E make_directory coverage/profraw
      COMMAND ${CMAKE_COMMAND} --build . --target test "LLVM_PROFILE_FILE=coverage/profraw/%p.profraw"
      COMMAND ${LLVM_PROFDATA_PATH} merge -sparse coverage/profraw/*.profraw -o coverage/coverage.profdata
      COMMAND ${LLVM_COV_PATH} show
        -instr-profile=coverage/coverage.profdata
        -format=html -output-dir=coverage/html
        -show-line-counts-or-regions
        -show-instantiation-summary
        ${ALL_TEST_BINS}
      COMMAND ${LLVM_COV_PATH} report
        -instr-profile=coverage/coverage.profdata
        ${ALL_TEST_BINS}
      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    )
    else()
      message(WARNING "llvm-cov and/or llvm-profdata not found! Coverage disabled.")
      return()
  elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
    # GCC
    set(LCOV_PATH ${CMAKE_CXX_COMPILER_DIR}/lcov)
    if(NOT EXISTS ${LCOV_PATH})
      find_program(LCOV_PATH lcov REQUIRED)
    endif()
  else()
    # Extract GCC version number and use matching gcov version
    execute_process(
      COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
      OUTPUT_VARIABLE GCC_VERSION
      OUTPUT_STRIP_TRAILING_WHITESPACE
    )
    set(GCOV_PATH ${CMAKE_CXX_COMPILER_DIR}/gcov-${GCC_VERSION})
    if(NOT EXISTS ${GCOV_PATH})
      find_program(GCOV_PATH gcov-${GCC_VERSION} REQUIRED)
    endif()
  
    add_custom_target(cov
      DEPENDS ${ALL_TEST_BINS}
      COMMAND ${CMAKE_COMMAND} -E make_directory coverage
      COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test
      COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --zerocounters
      COMMAND ${LCOV_PATH} --directory ${CMAKE_BINARY_DIR} --capture --output-file coverage/coverage.info
      COMMAND ${LCOV_PATH} --remove coverage/coverage.info '/usr/*' --output-file coverage/coverage.info
      COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/thirdparty/*' --output-file coverage/coverage.info
      COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/googletest/*' --output-file coverage/coverage.info
      COMMAND ${LCOV_PATH} --list coverage/coverage.info
      COMMAND ${LCOV_PATH} --directory . --zerocounters
      # Add initial capture before running tests
      COMMAND ${LCOV_PATH} --directory . --capture --initial --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.base --ignore-errors inconsistent
      # Run tests and capture coverage data
      COMMAND ctest --output-on-failure
      COMMAND ${LCOV_PATH} --directory . --capture --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info --ignore-errors inconsistent
      # Combine baseline and test coverage data
      COMMAND ${LCOV_PATH} --add-tracefile coverage/coverage.base --add-tracefile coverage/coverage.info --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.total
      # Only look at the coverage of the tests and duals library
      COMMAND ${LCOV_PATH} --extract coverage/coverage.total '*/tests/*' '*/duals/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
      # Remove unwanted paths
      #COMMAND ${LCOV_PATH} --remove coverage/coverage.total '/usr/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
      #COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/thirdparty/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
      #COMMAND ${LCOV_PATH} --remove coverage/coverage.info '*/googletest/*' --gcov-tool ${GCOV_PATH} --output-file coverage/coverage.info
      # Add --ignore-errors empty to prevent failure on empty coverage data
      COMMAND ${LCOV_PATH} --list coverage/coverage.info --ignore-errors empty --gcov-tool ${GCOV_PATH}
      WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
    )
  else()
    message(FATAL_ERROR "No coverage tool found for ${CMAKE_CXX_COMPILER_ID}")
  endif()

  add_custom_target(cov-html
@@ -291,4 +334,5 @@ if (CODE_COVERAGE)
    COMMAND ${CMAKE_COMMAND} -E echo "Coverage report generated at coverage/html/index.html"
    WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
  )

endif ()
Loading