gruggers 0.9.2

rust implementation of the grug language
Documentation
cmake_minimum_required(VERSION 3.16)
project(grug C)

# -----------------------------
# Compiler selection
# -----------------------------
# Respect CC if provided, default to clang
if(NOT CMAKE_C_COMPILER)
    set(CMAKE_C_COMPILER clang CACHE STRING "" FORCE)
endif()

message(STATUS "Compilation will use ${CMAKE_C_COMPILER_ID}")

# -----------------------------
# Base compiler flags
# -----------------------------

add_definitions(-D_CRT_SECURE_NO_WARNINGS)    
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if (MSVC)
	set(BASE_WARNINGS
		/W4
		/WX
		/analyze
        /w14242  # conversion loss
        /w14254  # conversion truncation
        /w14263  # uninitialized use
        /w14265  # class member padding / issues
        /w14287  # unsigned/negative mismatch
        /w14456  # shadowing (local)
        /w14457  # shadowing (parameter)
		/wd4068  # ignore unknown pragmas to ignore GCC diagnostic pragmas
	)
	set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} )
	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} )
	set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} )
	set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} )
	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} )
	set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR} )
	set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} )
	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} )
	set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR} )
else() 
	set(BASE_WARNINGS
		-g
		-Wall
		-Wextra
		-pedantic
		-Wconversion
		-Werror
		# -Wfatal-errors
		-Wstrict-prototypes
		-Wmissing-prototypes
		-Wshadow
		-Wuninitialized
		-Wunused-macros
	)
endif()

add_compile_options(${BASE_WARNINGS})

# Clang-specific flags
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
    add_compile_options(-gdwarf-4)
endif()

# -----------------------------
# Feature flags (env-controlled)
# -----------------------------

# ASAN
if(DEFINED ENV{ASAN})
    message(STATUS "ASAN was turned on")
    add_compile_options(-fsanitize=address,undefined)
    add_link_options(-fsanitize=address,undefined)
endif()

# COVERAGE
if(DEFINED ENV{COVERAGE})
    message(STATUS "COVERAGE was turned on")
    add_compile_options(--coverage)
    add_link_options(--coverage)

    file(GLOB GCDA_FILES "*.gcda")
    if(GCDA_FILES)
        file(REMOVE ${GCDA_FILES})
    endif()
endif()

# SHUFFLES
if(DEFINED ENV{SHUFFLES})
    message(STATUS "SHUFFLES=$ENV{SHUFFLES} was passed")
    add_compile_definitions(SHUFFLES=$ENV{SHUFFLES})
endif()

# BUILD_DIR
if(DEFINED ENV{BUILD_DIR})
    # Quote the string so C sees it as a literal
    message(STATUS "BUILD_DIR=\"$ENV{BUILD_DIR}\" was passed")
    add_compile_definitions("BUILD_DIR=\"$ENV{BUILD_DIR}\"")
endif()

# VALGRIND (runtime only, informational)
if(DEFINED ENV{VALGRIND})
    message(STATUS "VALGRIND was turned on")
endif()

# ANALYZE
if(DEFINED ENV{ANALYZE})
    message(STATUS "ANALYZE was turned on")
    if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
        add_compile_options(--analyzer)
    else()
        add_compile_options(--analyze)
    endif()
endif()

# -----------------------------
# Build tests.so (shared lib)
# -----------------------------
add_library(tests SHARED tests.c cJSON.c)

# Disable cJSON's explicit declspec exports.
# They cause our `CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON` to turn OFF.
target_compile_definitions(tests PRIVATE CJSON_HIDE_SYMBOLS)

set_target_properties(tests PROPERTIES
    OUTPUT_NAME tests
    POSITION_INDEPENDENT_CODE ON
)
if (DEFINED WIN32) 
    set_target_properties(tests PROPERTIES PREFIX "")
endif()

if (NOT(DEFINED WIN32))
	target_link_libraries(tests
		PRIVATE
			m
	)
endif()

# Needed to match -rdynamic behavior
if(UNIX AND NOT APPLE)
    target_link_options(tests PRIVATE -rdynamic)
endif()

# -----------------------------
# Build smoketest (executable)
# -----------------------------
add_executable(smoketest smoketest.c)

list(APPEND CMAKE_BUILD_RPATH ${CMAKE_CURRENT_BINARY_DIR})

# -----------------------------
# Run smoketest target
# -----------------------------
add_custom_target(run
    COMMAND
        $<$<BOOL:$ENV{VALGRIND}>:valgrind --quiet>
        $<TARGET_FILE:smoketest>
    DEPENDS smoketest
    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)

# -----------------------------
# Coverage report
# -----------------------------
if(DEFINED ENV{COVERAGE})
    add_custom_target(coverage
        COMMAND gcovr
            --gcov-executable "llvm-cov gcov"
            --html-details coverage.html
            --html-theme github.green
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        DEPENDS smoketest tests
    )
endif()