192 lines
7.8 KiB
CMake
192 lines
7.8 KiB
CMake
cmake_minimum_required(VERSION 3.16)
|
|
|
|
# std::filesystem needs macOS 10.15 or newer. Has to be set before project().
|
|
if(APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
|
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum macOS version")
|
|
endif()
|
|
|
|
project(antlrlab VERSION 1.0.0 LANGUAGES CXX)
|
|
|
|
set(CMAKE_CXX_STANDARD 17)
|
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
set(CMAKE_CXX_EXTENSIONS OFF)
|
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
|
endif()
|
|
|
|
# The ANTLR tool (Java) and the C++ runtime must be the same version, because
|
|
# the serialized grammar that the tool writes is read by the runtime.
|
|
set(ANTLR_VERSION "4.13.2" CACHE STRING "ANTLR version to build against")
|
|
|
|
option(ANTLRLAB_USE_SYSTEM_RUNTIME
|
|
"Use an installed ANTLR C++ runtime instead of downloading one" OFF)
|
|
option(ANTLRLAB_DOWNLOAD_JAR
|
|
"Download antlr-${ANTLR_VERSION}-complete.jar at configure time and use it by default" OFF)
|
|
if(MSVC)
|
|
option(ANTLRLAB_STATIC_CRT
|
|
"Visual C++: link the C++ runtime statically, so the program needs no redistributable" ON)
|
|
elseif(MINGW)
|
|
option(ANTLRLAB_STATIC_LINK
|
|
"MinGW: link libgcc, libstdc++ and winpthread statically, so no DLLs have to ship with the program" ON)
|
|
endif()
|
|
|
|
find_package(Threads REQUIRED)
|
|
|
|
# Visual C++: the runtime and antlrlab have to use the same C runtime library.
|
|
if(MSVC)
|
|
if(ANTLRLAB_STATIC_CRT)
|
|
set(WITH_STATIC_CRT ON CACHE BOOL "" FORCE) # read by the ANTLR runtime's own CMakeLists
|
|
set(ANTLRLAB_MSVC_RUNTIME "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
|
else()
|
|
set(WITH_STATIC_CRT OFF CACHE BOOL "" FORCE)
|
|
set(ANTLRLAB_MSVC_RUNTIME "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
|
|
endif()
|
|
endif()
|
|
|
|
# --------------------------------------------------------------- runtime ----
|
|
if(ANTLRLAB_USE_SYSTEM_RUNTIME)
|
|
find_path(ANTLR4_INCLUDE_DIR antlr4-runtime.h
|
|
PATH_SUFFIXES antlr4-runtime include/antlr4-runtime)
|
|
find_library(ANTLR4_LIBRARY NAMES antlr4-runtime antlr4-runtime-static)
|
|
if(NOT ANTLR4_INCLUDE_DIR OR NOT ANTLR4_LIBRARY)
|
|
message(FATAL_ERROR
|
|
"ANTLR C++ runtime not found. Install it, set ANTLR4_INCLUDE_DIR and "
|
|
"ANTLR4_LIBRARY, or configure without -DANTLRLAB_USE_SYSTEM_RUNTIME=ON.")
|
|
endif()
|
|
set(ANTLRLAB_RUNTIME_LIBS ${ANTLR4_LIBRARY})
|
|
set(ANTLRLAB_RUNTIME_INCLUDES ${ANTLR4_INCLUDE_DIR})
|
|
set(ANTLRLAB_RUNTIME_DEFS "")
|
|
else()
|
|
include(FetchContent)
|
|
set(ANTLR_BUILD_CPP_TESTS OFF CACHE BOOL "" FORCE)
|
|
set(ANTLR_BUILD_SHARED OFF CACHE BOOL "" FORCE)
|
|
set(ANTLR_BUILD_STATIC ON CACHE BOOL "" FORCE)
|
|
set(WITH_DEMO OFF CACHE BOOL "" FORCE)
|
|
set(ANTLR4_INSTALL OFF CACHE BOOL "" FORCE)
|
|
|
|
set(_antlr_fetch_args
|
|
URL "https://github.com/antlr/antlr4/archive/refs/tags/${ANTLR_VERSION}.tar.gz"
|
|
SOURCE_SUBDIR runtime/Cpp)
|
|
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
|
|
list(APPEND _antlr_fetch_args DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
|
|
endif()
|
|
FetchContent_Declare(antlr4 ${_antlr_fetch_args})
|
|
FetchContent_MakeAvailable(antlr4)
|
|
|
|
# The runtime forgets some standard #includes (<chrono> for one), which newer
|
|
# standard libraries, notably Visual C++'s, no longer paper over. Supply them.
|
|
if(TARGET antlr4_static)
|
|
set(_compat "${CMAKE_CURRENT_SOURCE_DIR}/cmake/antlr_runtime_compat.h")
|
|
if(MSVC)
|
|
target_compile_options(antlr4_static PRIVATE "/FI${_compat}")
|
|
else()
|
|
target_compile_options(antlr4_static PRIVATE -include "${_compat}")
|
|
endif()
|
|
endif()
|
|
|
|
set(ANTLRLAB_RUNTIME_LIBS antlr4_static)
|
|
set(ANTLRLAB_RUNTIME_INCLUDES "${antlr4_SOURCE_DIR}/runtime/Cpp/runtime/src")
|
|
set(ANTLRLAB_RUNTIME_DEFS ANTLR4CPP_STATIC)
|
|
endif()
|
|
|
|
# ------------------------------------------------------------------- jar ----
|
|
set(ANTLRLAB_JAR_PATH "")
|
|
if(ANTLRLAB_DOWNLOAD_JAR)
|
|
set(_jar "${CMAKE_BINARY_DIR}/antlr-${ANTLR_VERSION}-complete.jar")
|
|
if(NOT EXISTS "${_jar}")
|
|
# antlr.org first, then the copy in the ANTLR website's GitHub repository.
|
|
foreach(_url
|
|
"https://www.antlr.org/download/antlr-${ANTLR_VERSION}-complete.jar"
|
|
"https://raw.githubusercontent.com/antlr/website-antlr4/gh-pages/download/antlr-${ANTLR_VERSION}-complete.jar")
|
|
message(STATUS "Downloading ${_url}")
|
|
file(DOWNLOAD "${_url}" "${_jar}" STATUS _dl_status SHOW_PROGRESS)
|
|
list(GET _dl_status 0 _dl_code)
|
|
if(_dl_code EQUAL 0)
|
|
break()
|
|
endif()
|
|
file(REMOVE "${_jar}")
|
|
message(STATUS " failed: ${_dl_status}")
|
|
endforeach()
|
|
if(NOT EXISTS "${_jar}")
|
|
message(WARNING "Could not download the ANTLR jar. "
|
|
"Pass --antlr-jar or set ANTLR_JAR when running antlrlab.")
|
|
endif()
|
|
endif()
|
|
if(EXISTS "${_jar}")
|
|
file(TO_CMAKE_PATH "${_jar}" ANTLRLAB_JAR_PATH)
|
|
endif()
|
|
endif()
|
|
|
|
# ---------------------------------------------------------------- target ----
|
|
add_executable(antlrlab src/main.cpp)
|
|
target_include_directories(antlrlab PRIVATE src ${ANTLRLAB_RUNTIME_INCLUDES})
|
|
target_link_libraries(antlrlab PRIVATE ${ANTLRLAB_RUNTIME_LIBS} Threads::Threads)
|
|
target_compile_definitions(antlrlab PRIVATE
|
|
${ANTLRLAB_RUNTIME_DEFS}
|
|
LAB_VERSION="${PROJECT_VERSION}"
|
|
LAB_ANTLR_VERSION="${ANTLR_VERSION}")
|
|
if(ANTLRLAB_JAR_PATH)
|
|
target_compile_definitions(antlrlab PRIVATE LAB_DEFAULT_ANTLR_JAR="${ANTLRLAB_JAR_PATH}")
|
|
# Also put the jar next to the program: antlrlab looks there too, which keeps
|
|
# working when the build directory is moved, or its path has unusual characters.
|
|
add_custom_command(TARGET antlrlab POST_BUILD
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ANTLRLAB_JAR_PATH}" "$<TARGET_FILE_DIR:antlrlab>")
|
|
install(FILES "${ANTLRLAB_JAR_PATH}" DESTINATION bin)
|
|
endif()
|
|
|
|
# std::filesystem lives in a separate library in GCC 8 and older, and in Clang
|
|
# with libc++ 8 and older.
|
|
include(CheckCXXSourceCompiles)
|
|
set(CMAKE_REQUIRED_FLAGS "-std=c++17")
|
|
if(MSVC)
|
|
set(CMAKE_REQUIRED_FLAGS "/std:c++17")
|
|
endif()
|
|
check_cxx_source_compiles("#include <filesystem>
|
|
int main() { return std::filesystem::current_path().empty() ? 1 : 0; }" ANTLRLAB_FS_BUILTIN)
|
|
unset(CMAKE_REQUIRED_FLAGS)
|
|
if(NOT ANTLRLAB_FS_BUILTIN)
|
|
foreach(_fslib stdc++fs c++fs)
|
|
set(CMAKE_REQUIRED_LIBRARIES ${_fslib})
|
|
check_cxx_source_compiles("#include <filesystem>
|
|
int main() { return std::filesystem::current_path().empty() ? 1 : 0; }" ANTLRLAB_FS_${_fslib})
|
|
unset(CMAKE_REQUIRED_LIBRARIES)
|
|
if(ANTLRLAB_FS_${_fslib})
|
|
target_link_libraries(antlrlab PRIVATE ${_fslib})
|
|
break()
|
|
endif()
|
|
endforeach()
|
|
endif()
|
|
|
|
if(WIN32)
|
|
# Winsock (web UI), BCrypt (access token), Shell32 (command line, opening the
|
|
# browser), DbgHelp (stack traces in crash reports)
|
|
target_link_libraries(antlrlab PRIVATE ws2_32 bcrypt shell32 dbghelp)
|
|
target_compile_definitions(antlrlab PRIVATE _WIN32_WINNT=0x0601 NOMINMAX WIN32_LEAN_AND_MEAN)
|
|
endif()
|
|
|
|
# Crash reports print a stack trace; ENABLE_EXPORTS (-rdynamic) makes it show function names.
|
|
if(NOT WIN32)
|
|
set_target_properties(antlrlab PROPERTIES ENABLE_EXPORTS ON)
|
|
endif()
|
|
|
|
# The ANTLR runtime recurses deeply on real grammars. antlrlab runs it on a
|
|
# thread with a big stack it creates itself (src/isolate.hpp), so the main
|
|
# program only needs a normal stack; 8 MB matches the Linux default for the
|
|
# threads of the web server.
|
|
if(MSVC)
|
|
target_link_options(antlrlab PRIVATE /STACK:8388608)
|
|
set_property(TARGET antlrlab PROPERTY MSVC_RUNTIME_LIBRARY "${ANTLRLAB_MSVC_RUNTIME}")
|
|
target_compile_options(antlrlab PRIVATE /utf-8 /EHsc /permissive- /W3)
|
|
target_compile_definitions(antlrlab PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS)
|
|
else()
|
|
target_compile_options(antlrlab PRIVATE -Wall -Wextra)
|
|
if(MINGW)
|
|
target_link_options(antlrlab PRIVATE -Wl,--stack,8388608)
|
|
if(ANTLRLAB_STATIC_LINK)
|
|
target_link_options(antlrlab PRIVATE -static -static-libgcc -static-libstdc++)
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
install(TARGETS antlrlab RUNTIME DESTINATION bin)
|