# CMake version configuration
# (Note: The minimal version 3.16 is shipped with Ubuntu 20.04)
cmake_minimum_required(VERSION 3.16...3.19)

# Support older macOS versions. Needs to be set before calling project()!
# https://github.com/LibrePCB/LibrePCB/issues/1091
if(QT_MAJOR_VERSION EQUAL 5)
  set(CMAKE_OSX_DEPLOYMENT_TARGET
      "10.14"
      CACHE STRING "Minimum OS X deployment version"
  )
else()
  set(CMAKE_OSX_DEPLOYMENT_TARGET
      "10.15"
      CACHE STRING "Minimum OS X deployment version"
  )
endif()

# Fix missing libOpenGL.so.0 error of binary Linux releases, see
# https://github.com/probonopd/linuxdeployqt/issues/486.
set(OpenGL_GL_PREFERENCE LEGACY)

# WARNING:
# Read the release workflow documentation (at https://developers.librepcb.org)
# before making changes to the version numbers!

# Application version:
#  - Always three numbers (MAJOR.MINOR.PATCH)!
#  - Unstable (development) versions: Suffix "-unstable", e.g. "1.0.0-unstable"
#  - Release candidates: Suffix "-rc#", e.g. "1.0.0-rc3"
#  - Releases: No suffix, e.g. "1.0.0"
set(LIBREPCB_APP_VERSION "1.2.0")

# File format version:
#  - Must be equal to the major version of APP_VERSION!
#  - If APP_VERSION < 1.0.0: Two numbers, e.g. "0.2" for APP_VERSION=="0.2.x"
#  - If APP_VERSION >= 1.0.0: Only one number, e.g. "2" for APP_VERSION=="2.x.y"
set(LIBREPCB_FILE_FORMAT_VERSION "1")

# File format stable flag:
#  - On all non-release branches: false
#  - On release branches: true
# Note: Do not use a CMake boolean (ON / TRUE), use a C++ style boolean
# string instead ("true" / "false").
set(LIBREPCB_FILE_FORMAT_STABLE "true")

# Define project
project(librepcb LANGUAGES CXX)

# Configure module path
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})

# Global options
option(BUILD_TESTS "Build unit tests." ON)
option(BUILD_DISALLOW_WARNINGS
       "Disallow compiler warnings during build (build with -Werror)." OFF
)
option(BUILD_QTQUICK_TEST "Build the QML test window." ON)
option(UNBUNDLE_DXFLIB "Don't use vendored dxflib library." OFF)
option(UNBUNDLE_FONTOBENE_QT "Don't use vendored FontoBeneQt library." OFF)
option(UNBUNDLE_GTEST "Don't use vendored GoogleTest library." OFF)
option(UNBUNDLE_HOEDOWN "Don't use vendored Hoedown library." OFF)
option(UNBUNDLE_MUPARSER "Don't use vendored MuParser library." OFF)
option(UNBUNDLE_POLYCLIPPING "Don't use vendored Polyclipping library." OFF)
option(UNBUNDLE_QUAZIP "Don't use vendored QuaZip library." OFF)
option(UNBUNDLE_ALL "Don't use any vendored library." OFF)
option(USE_GLU "Include features depending on OpenGL Utility Library (GLU)." ON)
option(USE_OPENCASCADE "Include features depending on OpenCascade." ON)

# Deprecated options
if(UNBUNDLE_FONTOBENE_QT5)
  message(
    WARNING
      "Option 'UNBUNDLE_FONTOBENE_QT5' is deprecated and will be removed in \
      the next release. Please replace the dependency fontobene-qt5 by its \
      successor fontobene-qt and use the new option 'UNBUNDLE_FONTOBENE_QT'."
  )
  set(UNBUNDLE_FONTOBENE_QT ${UNBUNDLE_FONTOBENE_QT5})
endif()

# Create a release build by default
include(DefaultBuildType)

# Force static linking for local libs
set(BUILD_SHARED_LIBS
    OFF
    CACHE BOOL "Link dynamically against local libraries." FORCE
)

# Auto-include current directory
set(CMAKE_INCLUDE_CURRENT_DIR ON)

# If Qt version is not explicitly specified, automatically determine it
if(NOT QT_MAJOR_VERSION)
  find_package(Qt NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
  set(QT_MAJOR_VERSION ${Qt_VERSION_MAJOR})
endif()
set(QT "Qt${QT_MAJOR_VERSION}")
set(PARSEAGLE_QT_MAJOR_VERSION ${QT_MAJOR_VERSION})

# Use C++11 (Qt5) or C++17 (Qt6)
if(QT_MAJOR_VERSION EQUAL 6)
  set(CMAKE_CXX_STANDARD 17)
else()
  set(CMAKE_CXX_STANDARD 11)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Include GNU install dirs variables
include(GNUInstallDirs)

# Workaround for builds on macOS with Qt installed through homebrew
# https://github.com/Homebrew/homebrew-core/issues/8392#issuecomment-325226494
if(APPLE AND EXISTS /usr/local/opt/qt5)
  # Homebrew installs Qt5 (up to at least 5.9.1) in
  # /usr/local/qt5, ensure it can be found by CMake since
  # it is not in the default /usr/local prefix.
  list(APPEND CMAKE_PREFIX_PATH "/usr/local/opt/qt5")
endif()

# Create "common" interface library which is used for DRY configuration of
# build flags.
add_library(common INTERFACE)
target_compile_options(common INTERFACE -Wall -Wextra -Wpedantic)
if(BUILD_DISALLOW_WARNINGS)
  target_compile_options(common INTERFACE -Werror)
endif()

# The TypeSafe library causes some compiler warnings which are not of
# interest, so let's suppress them.
target_compile_options(common INTERFACE -Wno-noexcept-type)

# Clang emits some warnings within the muParser library when compiling with
# -Wpedantic, so let's suppress these warnings when compiling with Clang.
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  target_compile_options(common INTERFACE -Wno-nested-anon-types)
endif()

# Avoid "file too big" error for debug builds on Windows.
if(WIN32)
  target_compile_options(common INTERFACE $<$<CONFIG:Debug>:-Wa,-mbig-obj>)
endif()

# Enforce UNICODE on Windows to avoid an incompatibility with OpenCascade.
if(WIN32)
  add_definitions(-DUNICODE -D_UNICODE)
endif()

# Disable Qt functions which are deprecated in Qt <= 5.12 to enforce us
# migrating away from them. Always set this to the lowest Qt version we want
# to support.
add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x050C00)

# Not sure what we should do with deprecation warnings. Better keeping
# backwards compatibility with already existing & supported environments
# instead of forward compatibility with not yet existing environments, no?
add_definitions(
  -DQT_NO_DEPRECATED_WARNINGS # Qt
  -DGL_SILENCE_DEPRECATION # OpenGL
  -DOCCT_NO_DEPRECATED # OpenCascade
)

# Determine required Qt components
set(QT_COMPONENTS
    Concurrent
    Core
    Gui
    LinguistTools
    Network
    OpenGL
    PrintSupport
    Sql
    Svg
    Widgets
)
if(QT_MAJOR_VERSION GREATER 5)
  list(APPEND QT_COMPONENTS OpenGLWidgets)
endif()
if(BUILD_QTQUICK_TEST)
  list(APPEND QT_COMPONENTS Quick QuickControls2)
endif()
if(BUILD_TESTS)
  list(APPEND QT_COMPONENTS Test)
endif()

# Find Qt
find_package(${QT} 5.12.0 REQUIRED COMPONENTS ${QT_COMPONENTS})
set(QT_VERSION "${${QT}_VERSION}")
message(STATUS "Building LibrePCB with Qt ${QT_VERSION}")
if(QT_MAJOR_VERSION EQUAL 5)
  message(
    DEPRECATION
      "Building with Qt5 is considered as deprecated and will be removed in
      an upcoming release. Please use Qt6 instead."
  )
endif()

# For the ParsEagle library, use the same Qt version as for LibrePCB
set(PARSEAGLE_QT_MAJOR_VERSION ${QT_MAJOR_VERSION})

# Find third party libraries
find_package(DelaunayTriangulation REQUIRED)
find_package(Dxflib REQUIRED)
find_package(FontoBeneQt REQUIRED)
find_package(GLU REQUIRED)
find_package(MuParser REQUIRED)
find_package(OpenCascade REQUIRED)
find_package(Optional REQUIRED)
find_package(Polyclipping REQUIRED)
find_package(QuaZip REQUIRED)
find_package(TypeSafe REQUIRED)
if(BUILD_TESTS)
  find_package(GTest REQUIRED)
endif()
# Hoedown is only needed on Qt <5.14
if(QT_VERSION VERSION_LESS 5.14)
  message(STATUS "Qt <5.14 detected, using Hoedown for markdown support")
  find_package(Hoedown REQUIRED)
endif()

# Add libs
add_subdirectory(libs/librepcb/core)
add_subdirectory(libs/librepcb/editor)
add_subdirectory(libs/librepcb/eagleimport)
add_subdirectory(libs/librepcb/kicadimport)
add_subdirectory(libs/parseagle)

# Add apps
add_subdirectory(apps/librepcb)
add_subdirectory(apps/librepcb-cli)

# Add unittests
if(BUILD_TESTS)
  add_subdirectory(tests/unittests)
endif()

# Generate translation file target
set(LIBREPCB_QM_FILES_DIR "${CMAKE_BINARY_DIR}/i18n")
file(MAKE_DIRECTORY "${LIBREPCB_QM_FILES_DIR}")
file(
  GLOB LIBREPCB_TS_FILES
  RELATIVE ${CMAKE_SOURCE_DIR}
  i18n/librepcb_*.ts
)
set_source_files_properties(
  ${LIBREPCB_TS_FILES} PROPERTIES OUTPUT_LOCATION "${LIBREPCB_QM_FILES_DIR}"
)
if(QT_VERSION VERSION_LESS 5.12)
  # Qt <5.12 doesn't support OPTIONS
  qt5_add_translation(LIBREPCB_QM_FILES ${LIBREPCB_TS_FILES})
elseif(QT_VERSION VERSION_LESS 6.0)
  qt5_add_translation(LIBREPCB_QM_FILES ${LIBREPCB_TS_FILES} OPTIONS -silent)
else()
  qt6_add_translation(LIBREPCB_QM_FILES ${LIBREPCB_TS_FILES} OPTIONS -silent)
endif()
add_custom_target(librepcb_translations DEPENDS ${LIBREPCB_QM_FILES})
add_dependencies(librepcb librepcb_translations)

# Install target for shared files
file(
  GLOB SHARE_DIRS
  LIST_DIRECTORIES true
  RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
  share/*
)
foreach(d ${SHARE_DIRS})
  if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${d}")
    install(
      DIRECTORY ${d}
      DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}
      REGEX "/\.(git|gitattributes|gitignore)$" EXCLUDE
    )
  endif()
endforeach()
install(
  DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/i18n/share/
  DESTINATION ${CMAKE_INSTALL_DATAROOTDIR} OPTIONAL
)
install(
  DIRECTORY ${CMAKE_BINARY_DIR}/i18n
  DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/librepcb
)

# Windows installer configuration
configure_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/dist/innosetup/config.iss.in
  ${CMAKE_BINARY_DIR}/dist/innosetup/config.iss @ONLY
)
add_custom_target(
  librepcb_installer DEPENDS ${CMAKE_BINARY_DIR}/dist/innosetup/config.iss
)
add_dependencies(librepcb librepcb_installer)
