cmake_minimum_required (VERSION 3.0)

cmake_policy(SET CMP0054 NEW)
cmake_policy(SET CMP0048 NEW)


set_property(GLOBAL PROPERTY USE_FOLDERS ON)

include(GNUInstallDirs)

# Define Version
set(LIB3MF_VERSION_MAJOR 2)        # increase on every backward-compatibility breaking change of the API
set(LIB3MF_VERSION_MINOR 4)        # increase on every backward compatible change of the API
set(LIB3MF_VERSION_MICRO 1)        # increase on on every change that does not alter the API
set(LIB3MF_VERSION_PRERELEASE "")  # denotes pre-release information of a version of lib3mf
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
project(lib3mf
  VERSION ${LIB3MF_VERSION_MAJOR}.${LIB3MF_VERSION_MINOR}.${LIB3MF_VERSION_MICRO}
  DESCRIPTION "An implementation of the 3D Manufacturing Format file standard"
)

find_program(buildcache_program buildcache)
if(buildcache_program)
  set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${buildcache_program}")
endif()

set(CMAKE_INSTALL_BINDIR bin CACHE PATH "directory for installing binary files")
set(CMAKE_INSTALL_LIBDIR lib CACHE PATH "directory for installing library files")
set(CMAKE_INSTALL_INCLUDEDIR include/lib3mf CACHE PATH "directory for installing header files")

option(USE_INCLUDED_ZLIB "Use included zlib" ON)
option(USE_INCLUDED_LIBZIP "Use included libzip" ON)
option(USE_INCLUDED_SSL "Use included libressl" ON)
option(BUILD_FOR_CODECOVERAGE "Build for code coverage analysis" OFF)
option(STRIP_BINARIES "Strip binaries (on non-apple)" ON)
option(USE_PLATFORM_UUID "Use UUID geneator that is provided by the OS (always ON for Windows)" OFF)

add_compile_options($<$<CXX_COMPILER_ID:MSVC>:/MP>)
set (CMAKE_CXX_STANDARD 17)

if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
  # using GCC
  add_definitions(-DBUILD_DLL)
  add_compile_options(-Wall)
  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
    add_compile_options(-g)
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Og")
  else()
    SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O2")
  endif(CMAKE_BUILD_TYPE MATCHES DEBUG)
  
elseif ("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
  # using GCC
  add_definitions(-DBUILD_DLL)
  add_compile_options(-Wall) 
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O2")
  set(CMAKE_MACOSX_RPATH ON)
endif()

if (${MSVC})
  # using Visual Studio C++

  # this ensures that the min/max macros of minwindef.h are not used
  add_definitions(-DNOMINMAX)

  #add_definitions(/W3)

  # add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS)
  # set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
  # set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
endif()

if (BUILD_FOR_CODECOVERAGE)
  SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall -fprofile-arcs -ftest-coverage -DCREATEJOURNAL")
  SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -Wall -W -fprofile-arcs -ftest-coverage")
  SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-arcs -ftest-coverage")
endif()


set(CMAKE_CURRENT_SOURCE_DIR_AUTOGENERATED ${CMAKE_CURRENT_SOURCE_DIR}/Autogenerated)
set(CMAKE_CURRENT_BINARY_DIR_AUTOGENERATED ${CMAKE_CURRENT_BINARY_DIR})
set(CMAKE_TEMP_HEADER_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/AutomaticComponentToolkit/Lib3MF_component")
set(ACT_GENERATED_SOURCE
  ${CMAKE_CURRENT_SOURCE_DIR_AUTOGENERATED}/Source/lib3mf_interfaceexception.cpp
  ${CMAKE_CURRENT_SOURCE_DIR_AUTOGENERATED}/Source/lib3mf_interfacewrapper.cpp
  ${CMAKE_CURRENT_SOURCE_DIR_AUTOGENERATED}/Source/lib3mf_interfacejournal.cpp
)

include(Source/CMakeLists.txt)
#########################################################
# Set version info
if(DEFINED ENV{BUILD_NUMBER})
  set(BUILD_NUMBER $ENV{BUILD_NUMBER})
else()
  set(BUILD_NUMBER 0)
endif()

if (WIN32)
  message("BUILD_NUMBER ... " ${BUILD_NUMBER})
  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/Include/VersionInfo)

  include(generate_product_version)
    generate_product_version(
    VERSION_FILES_OUTPUTLOCATION
    NAME "lib3mf"
    FILE_DESCRIPTION "lib3mf is an implementation of the 3D Manufacturing Format file standard"
    BUNDLE "3MF Consortium"
    VERSION_MAJOR ${LIB3MF_VERSION_MAJOR}
    VERSION_MINOR ${LIB3MF_VERSION_MINOR}
    VERSION_PATCH ${LIB3MF_VERSION_MICRO}
    VERSION_REVISION ${BUILD_NUMBER}
    PRODUCT_VERSION_MAJOR ${LIB3MF_VERSION_MAJOR}
    PRODUCT_VERSION_MINOR ${LIB3MF_VERSION_MINOR}
    PRODUCT_VERSION_PATCH ${LIB3MF_VERSION_MICRO}
    PRODUCT_VERSION_REVISION ${LIB3MF_VERSION_PRERELEASE}
    COMPANY_NAME "3MF Consortium"
  )
  message("VERSION_FILES_OUTPUTLOCATION ... " ${VERSION_FILES_OUTPUTLOCATION})
else()
  set(VERSION_FILES_OUTPUTLOCATION "")
endif()


#########################################################
# Shared library
add_library(${PROJECT_NAME} SHARED ${SRCS_COMMON} ${HDRS_COMMON}
  ${ACT_GENERATED_SOURCE}
  ${VERSION_FILES_OUTPUTLOCATION}
)

if (${MSVC})
  # using Visual Studio C++

  # Allow unnamed structs and ensures that the min/max macros of minwindef.h are not used

  # Note the generator expression to limit the scope to c++ compiler, otherwise the RC compiler would get the arguments as well.
  # Works with ninja, but not with the VS build generators
  if (CMAKE_GENERATOR MATCHES "Ninja")
    target_compile_options(${PROJECT_NAME} PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-DNOMINMAX /Wv:18>)
  else()
    target_compile_options(${PROJECT_NAME} PUBLIC -DNOMINMAX /Wv:18)
  endif()
endif()

SOURCE_GROUP("Source Files\\Autogenerated" FILES ${ACT_GENERATED_SOURCE})


file(GLOB
    LIBS_INCLUDE
    LIST_DIRECTORIES true
    ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/*/Include
)
list(FILTER LIBS_INCLUDE EXCLUDE REGEX "zlib|libzip|libressl")
target_include_directories(${PROJECT_NAME} PRIVATE ${LIBS_INCLUDE})

# allow FASTFLOAT_ALLOWS_LEADING_PLUS
add_definitions(-DFASTFLOAT_ALLOWS_LEADING_PLUS=1)

target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR_AUTOGENERATED}/Source)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Include/API)
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Include)

if (USE_INCLUDED_LIBZIP)
    # Something goes here to check if submodules exist and initialize the submodules if it does not
    target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/libzip/Include)
    if(MSVC)
      target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS)
      target_compile_definitions(${PROJECT_NAME} PRIVATE _CRT_NONSTDC_NO_DEPRECATE)
    endif()
    if(WIN32)
      target_link_libraries(${PROJECT_NAME} PRIVATE advapi32)
      # disable win32 build failing 'initializing': conversion from 'zip_uint64_t' to 'size_t', possible loss of data 
      if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
        target_compile_options(${PROJECT_NAME} PRIVATE /wd4244)
      endif()
    endif()

    # create libzip autogenerated platform specific headers
    if(NOT EXISTS ${CMAKE_BINARY_DIR}/libzip)
    execute_process(
      COMMAND ${CMAKE_COMMAND} "-DZLIB_INCLUDE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/submodules/zlib" 
            "-DZLIB_LIBRARY=zlibstatic" "-DENABLE_COMMONCRYPTO=OFF" "-DENABLE_GNUTLS=OFF" "-DENABLE_MBEDTLS=OFF" 
            "-DENABLE_OPENSSL=OFF" "-DENABLE_WINDOWS_CRYPTO=OFF" 
            "-DENABLE_BZIP2=OFF" "-DENABLE_LZMA=OFF" "-DENABLE_ZSTD=OFF"
            "-DBUILD_TOOLS=OFF" "-DBUILD_REGRESS=OFF"
            "-DBUILD_EXAMPLES=OFF" "-DBUILD_DOC=OFF" "-DBUILD_SHARED_LIBS=OFF" "-DLIBZIP_DO_INSTALL=OFF"
            "-S" "${CMAKE_CURRENT_SOURCE_DIR}/submodules/libzip" "-B" "${CMAKE_CURRENT_BINARY_DIR}/libzip"   
      RESULT_VARIABLE CMD_ERROR
      OUTPUT_QUIET)
    MESSAGE( STATUS "CMD_ERROR:" ${CMD_ERROR})
    endif()
    target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/libzip)

    if (UNIX OR MINGW)
      target_compile_options(${PROJECT_NAME} PRIVATE "-DHAVE_FSEEKO")
      target_compile_options(${PROJECT_NAME} PRIVATE "-DHAVE_FTELLO")
      target_compile_options(${PROJECT_NAME} PRIVATE "-DHAVE_STRCASECMP")
      target_compile_options(${PROJECT_NAME} PRIVATE "-DHAVE_UNISTD_H")
    endif()

else()
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(LIBZIP REQUIRED libzip)
    target_link_libraries(${PROJECT_NAME} ${LIBZIP_LIBRARIES})
endif()


if (USE_INCLUDED_ZLIB)
    target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/zlib/Include)
else()
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(ZLIB REQUIRED zlib)
    target_link_libraries(${PROJECT_NAME} ${ZLIB_LIBRARIES})
endif()


target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/submodules/fast_float/include)


set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" IMPORT_PREFIX "" )
# This makes sure symbols are exported
target_compile_options(${PROJECT_NAME} PRIVATE "-D__LIB3MF_EXPORTS")
# The following two properties are crucial to reduce the number of undesirably exported symbols
set_target_properties(${PROJECT_NAME} PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
set_target_properties(${PROJECT_NAME} PROPERTIES VISIBILITY_INLINES_HIDDEN ON)

set(STARTUPPROJECT ${PROJECT_NAME})

#########################################################
if (UNIX OR MINGW)
  # Uncomment the following to put the version info into the .so-file.
  set_target_properties(${PROJECT_NAME} PROPERTIES VERSION "${LIB3MF_VERSION_MAJOR}.${LIB3MF_VERSION_MINOR}.${LIB3MF_VERSION_MICRO}.${BUILD_NUMBER}")
  set_target_properties(${PROJECT_NAME} PROPERTIES SOVERSION "${LIB3MF_VERSION_MAJOR}")
  if (STRIP_BINARIES AND NOT APPLE)
    set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS -s)
  endif()
else()
  # wd4996 masks the deprecated-warning
  target_compile_options(${PROJECT_NAME} PUBLIC "$<$<CONFIG:DEBUG>:/Od;/Ob0;/sdl;/W3;/WX;/FC;/wd4996>")
  target_compile_options(${PROJECT_NAME} PUBLIC "$<$<CONFIG:RELEASE>:/O2;/sdl;/WX;/Oi;/Gy;/FC;/wd4996>")
endif()

## UUID
if(WIN32)
	target_compile_definitions(${PROJECT_NAME} PRIVATE GUID_WINDOWS)
	target_link_libraries(${PROJECT_NAME} PRIVATE ole32 uuid)
else()
  if (USE_PLATFORM_UUID)
    if (APPLE)
      target_compile_definitions(${PROJECT_NAME} PRIVATE GUID_CFUUID)
      target_link_libraries(${PROJECT_NAME} "-framework Foundation")
    else()
      target_compile_definitions(${PROJECT_NAME} PRIVATE GUID_LIBUUID)
      target_link_libraries(${PROJECT_NAME} PRIVATE uuid)
    endif()
  else()
    target_compile_definitions(${PROJECT_NAME} PRIVATE GUID_CUSTOM)
  endif()
endif(WIN32)

configure_file(lib3mf.pc.in lib3mf.pc @ONLY)
install(FILES ${CMAKE_BINARY_DIR}/lib3mf.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
install(FILES cmake/lib3mfConfig.cmake
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/lib3mf)
install(TARGETS ${PROJECT_NAME}
  ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
  LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR_AUTOGENERATED}/Bindings DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")

#########################################################
option(LIB3MF_TESTS "Switch whether the tests of lib3mf should be build" ON)
message("LIB3MF_TESTS ... " ${LIB3MF_TESTS})

if(LIB3MF_TESTS)
  enable_testing()
  add_subdirectory(Tests)
endif()

#########################################################
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
  IF(${CMAKE_VERSION} VERSION_LESS 3.6.3)
    MESSAGE ("Note: You need to manually select a StartUp-project in Visual Studio.")
  ELSE()
    set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${STARTUPPROJECT})
  ENDIF()
endif()


#########################################################
set(CPACK_PACKAGE_NAME "lib3mf")
set(CPACK_PACKAGE_VENDOR "3MF Consortium")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "lib3mf - An implementation of the 3D Manufacturing Format file standard")
set(CPACK_PACKAGE_VERSION "${LIB3MF_VERSION_MAJOR}.${LIB3MF_VERSION_MINOR}.${LIB3MF_VERSION_MICRO}")
set(CPACK_PACKAGE_VERSION_MAJOR "${LIB3MF_VERSION_MAJOR}")
set(CPACK_PACKAGE_VERSION_MINOR "${LIB3MF_VERSION_MINOR}")
set(CPACK_PACKAGE_VERSION_PATCH "${LIB3MF_VERSION_MICRO}")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64")
set(CPACK_PACKAGE_CONTACT "lib3mf@3mf.io")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "3MF Consortium")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-Source")

#########################################################
include(CPack)
