diff --git a/runtime/Cpp/cmake/ExternalAntlr4Cpp.cmake b/runtime/Cpp/cmake/ExternalAntlr4Cpp.cmake index fc926804e..5c3d406ae 100644 --- a/runtime/Cpp/cmake/ExternalAntlr4Cpp.cmake +++ b/runtime/Cpp/cmake/ExternalAntlr4Cpp.cmake @@ -1,223 +1,115 @@ -# -*- mode:cmake -*- -# -# This Cmake file is for those using a superbuild Cmake Pattern, it -# will download the tools and build locally -# -# use 2the antlr4cpp_process_grammar to support multiple grammars in the -# same project -# -# - Getting quicky started with Antlr4cpp -# -# Here is how you can use this external project to create the antlr4cpp -# demo to start your project off. -# -# create your project source folder somewhere. e.g. ~/srcfolder/ -# + make a subfolder cmake -# + Copy this file to srcfolder/cmake -# + cut below and use it to create srcfolder/CMakeLists.txt, -# + from https://github.com/DanMcLaughlin/antlr4/tree/master/runtime/Cpp/demo Copy main.cpp, TLexer.g4 and TParser.g4 to ./srcfolder/ -# -# next make a build folder e.g. ~/buildfolder/ -# from the buildfolder, run cmake ~/srcfolder; make -# -############################################################### -# # minimum required CMAKE version -# CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12.2 FATAL_ERROR) -# -# LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ) -# -# # compiler must be 11 or 14 -# SET (CMAKE_CXX_STANDARD 11) -# -# # set variable pointing to the antlr tool that supports C++ -# set(ANTLR4CPP_JAR_LOCATION /home/user/antlr4-4.5.4-SNAPSHOT.jar) -# # add external build for antlrcpp -# include( ExternalAntlr4Cpp ) -# # add antrl4cpp artifacts to project environment -# include_directories( ${ANTLR4CPP_INCLUDE_DIRS} ) -# link_directories( ${ANTLR4CPP_LIBS} ) -# message(STATUS "Found antlr4cpp libs: ${ANTLR4CPP_LIBS} and includes: ${ANTLR4CPP_INCLUDE_DIRS} ") -# -# # Call macro to add lexer and grammar to your build dependencies. -# antlr4cpp_process_grammar(demo antlrcpptest -# ${CMAKE_CURRENT_SOURCE_DIR}/TLexer.g4 -# ${CMAKE_CURRENT_SOURCE_DIR}/TParser.g4) -# # include generated files in project environment -# include_directories(${antlr4cpp_include_dirs_antlrcpptest}) -# -# # add generated grammar to demo binary target -# add_executable(demo main.cpp ${antlr4cpp_src_files_antlrcpptest}) -# add_dependencies(demo antlr4cpp antlr4cpp_generation_antlrcpptest) -# target_link_libraries(demo antlr4-runtime) -# -############################################################### +cmake_minimum_required(VERSION 3.7) -CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12.2) -PROJECT(antlr4cpp_fetcher CXX) -INCLUDE(ExternalProject) -FIND_PACKAGE(Git REQUIRED) +include(ExternalProject) -# only JRE required -FIND_PACKAGE(Java COMPONENTS Runtime REQUIRED) - -############ Download and Generate runtime ################# -set(ANTLR4CPP_EXTERNAL_ROOT ${CMAKE_BINARY_DIR}/externals/antlr4cpp) - -# external repository -# GIT_REPOSITORY https://github.com/antlr/antlr4.git -set(ANTLR4CPP_EXTERNAL_REPO "https://github.com/antlr/antlr4.git") -set(ANTLR4CPP_EXTERNAL_TAG "4.7.1") - -if(NOT EXISTS "${ANTLR4CPP_JAR_LOCATION}") - message(FATAL_ERROR "Unable to find antlr tool. ANTLR4CPP_JAR_LOCATION:${ANTLR4CPP_JAR_LOCATION}") +set(ANTLR4_ROOT ${CMAKE_CURRENT_BINARY_DIR}/antlr4_runtime/src/antlr4_runtime) +set(ANTLR4_INCLUDE_DIRS ${ANTLR4_ROOT}/runtime/Cpp/runtime/src) +set(ANTLR4_GIT_REPOSITORY https://github.com/antlr/antlr4.git) +if(NOT DEFINED ANTLR4_TAG) + # Set to branch name to keep library updated at the cost of needing to rebuild after 'clean' + # Set to commit hash to keep the build stable and does not need to rebuild after 'clean' + set(ANTLR4_TAG master) endif() -# default path for source files -if (NOT ANTLR4CPP_GENERATED_SRC_DIR) - set(ANTLR4CPP_GENERATED_SRC_DIR ${CMAKE_BINARY_DIR}/antlr4cpp_generated_src) +if(${CMAKE_GENERATOR} MATCHES "Visual Studio.*") + set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/dist/$(Configuration)) +else() + set(ANTLR4_OUTPUT_DIR ${ANTLR4_ROOT}/runtime/Cpp/dist) endif() -# !TODO! This should probably check with Cmake Find first? -# set(ANTLR4CPP_JAR_LOCATION ${ANTLR4CPP_EXTERNAL_ROOT}/${ANTLR4CPP_JAR_NAME}) -# -# !TODO! Ensure Antlr tool available - copy from internet -# -# # !TODO! this shold be calculated based on the tags -# if (NOT ANTLR4CPP_JAR_NAME) -# # default location to find antlr Java binary -# set(ANTLR4CPP_JAR_NAME antlr4-4.5.4-SNAPSHOT.jar) -# endif() -# -# if(NOT EXISTS "${ANTLR4CPP_JAR_LOCATION}") -# # download Java tool if not installed -# ExternalProject_ADD( -# #--External-project-name------ -# antlrtool -# #--Core-directories----------- -# PREFIX ${ANTLR4CPP_EXTERNAL_ROOT} -# #--Download step-------------- -# DOWNLOAD_DIR ${ANTLR4CPP_EXTERNAL_ROOT} -# DOWNLOAD_COMMAND "" -# # URL http://www.antlr.org/download/${ANTLR4CPP_JAR_NAME} -# # antlr4-4.5.4-SNAPSHOT.jar -# # GIT_TAG v4.5.4 -# TIMEOUT 10 -# LOG_DOWNLOAD ON -# #--Update step---------- -# # UPDATE_COMMAND ${GIT_EXECUTABLE} pull -# #--Patch step---------- -# # PATCH_COMMAND sh -c "cp /scripts/CMakeLists.txt " -# #--Configure step------------- -# CMAKE_ARGS "" -# CONFIGURE_COMMAND "" -# LOG_CONFIGURE ON -# #--Build step----------------- -# BUILD_COMMAND "" -# LOG_BUILD ON -# #--Install step--------------- -# INSTALL_COMMAND "" -# ) -# # Verify Antlr Available -# if(NOT EXISTS "${ANTLR4CPP_JAR_LOCATION}") -# message(FATAL_ERROR "Unable to find ANTLR4CPP_JAR_LOCATION:${ANTLR4CPP_JAR_LOCATION} -> ${ANTLR4CPP_JAR_NAME} not in ${ANTLR4CPP_DIR} ") -# endif() -# endif() - -# download runtime environment -ExternalProject_ADD( - #--External-project-name------ - antlr4cpp - #--Depend-on-antrl-tool----------- - # DEPENDS antlrtool - #--Core-directories----------- - PREFIX ${ANTLR4CPP_EXTERNAL_ROOT} - #--Download step-------------- - GIT_REPOSITORY ${ANTLR4CPP_EXTERNAL_REPO} - # GIT_TAG ${ANTLR4CPP_EXTERNAL_TAG} - TIMEOUT 10 - LOG_DOWNLOAD ON - #--Update step---------- - UPDATE_COMMAND ${GIT_EXECUTABLE} pull - #--Patch step---------- - # PATCH_COMMAND sh -c "cp /scripts/CMakeLists.txt " - #--Configure step------------- - CONFIGURE_COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release -DANTLR4CPP_JAR_LOCATION=${ANTLR4CPP_JAR_LOCATION} -DBUILD_SHARED_LIBS=ON -BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_SOURCE_DIR:PATH=/runtime/Cpp /runtime/Cpp - LOG_CONFIGURE ON - #--Build step----------------- - # BUILD_COMMAND ${CMAKE_MAKE_PROGRAM} - LOG_BUILD ON - #--Install step--------------- - # INSTALL_COMMAND "" - # INSTALL_DIR ${CMAKE_BINARY_DIR}/ - #--Install step--------------- - # INSTALL_COMMAND "" -) - -ExternalProject_Get_Property(antlr4cpp INSTALL_DIR) - -list(APPEND ANTLR4CPP_INCLUDE_DIRS ${INSTALL_DIR}/include/antlr4-runtime) -foreach(src_path misc atn dfa tree support) - list(APPEND ANTLR4CPP_INCLUDE_DIRS ${INSTALL_DIR}/include/antlr4-runtime/${src_path}) -endforeach(src_path) - -set(ANTLR4CPP_LIBS "${INSTALL_DIR}/lib") - -# antlr4_shared ${INSTALL_DIR}/lib/libantlr4-runtime.so -# antlr4_static ${INSTALL_DIR}/lib/libantlr4-runtime.a - -############ Generate runtime ################# -# macro to add dependencies to target -# -# Param 1 project name -# Param 1 namespace (postfix for dependencies) -# Param 2 Lexer file (full path) -# Param 3 Parser File (full path) -# -# output -# -# antlr4cpp_src_files_{namespace} - src files for add_executable -# antlr4cpp_include_dirs_{namespace} - include dir for generated headers -# antlr4cpp_generation_{namespace} - for add_dependencies tracking - -macro(antlr4cpp_process_grammar - antlr4cpp_project - antlr4cpp_project_namespace - antlr4cpp_grammar_lexer - antlr4cpp_grammar_parser) - - if(EXISTS "${ANTLR4CPP_JAR_LOCATION}") - message(STATUS "Found antlr tool: ${ANTLR4CPP_JAR_LOCATION}") +if(MSVC) + set(ANTLR4_STATIC_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/antlr4-runtime-static.lib) + set(ANTLR4_SHARED_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/antlr4-runtime.lib) + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/antlr4-runtime.dll) +else() + set(ANTLR4_STATIC_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.a) + if(MINGW) + set(ANTLR4_SHARED_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a) + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll) + elseif(CYGWIN) + set(ANTLR4_SHARED_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.dll.a) + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/cygantlr4-runtime-4.7.1.dll) else() - message(FATAL_ERROR "Unable to find antlr tool. ANTLR4CPP_JAR_LOCATION:${ANTLR4CPP_JAR_LOCATION}") + set(ANTLR4_RUNTIME_LIBRARIES + ${ANTLR4_OUTPUT_DIR}/libantlr4-runtime.so) endif() +endif() - add_custom_target("antlr4cpp_generation_${antlr4cpp_project_namespace}" - COMMAND - ${CMAKE_COMMAND} -E make_directory ${ANTLR4CPP_GENERATED_SRC_DIR} - COMMAND - "${Java_JAVA_EXECUTABLE}" -jar "${ANTLR4CPP_JAR_LOCATION}" -Werror -Dlanguage=Cpp -listener -visitor -o "${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}" -package ${antlr4cpp_project_namespace} "${antlr4cpp_grammar_lexer}" "${antlr4cpp_grammar_parser}" - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" - DEPENDS "${antlr4cpp_grammar_lexer}" "${antlr4cpp_grammar_parser}" - ) +if(${CMAKE_GENERATOR} MATCHES ".* Makefiles") + # This avoids + # 'warning: jobserver unavailable: using -j1. Add '+' to parent make rule.' + set(ANTLR4_BUILD_COMMAND $(MAKE)) +elseif(${CMAKE_GENERATOR} MATCHES "Visual Studio.*") + set(ANTLR4_BUILD_COMMAND + ${CMAKE_COMMAND} + --build . + --config $(Configuration) + --target) +else() + set(ANTLR4_BUILD_COMMAND + ${CMAKE_COMMAND} + --build . + --target) +endif() - # Find all the input files - FILE(GLOB generated_files ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}/*.cpp) +ExternalProject_Add( + antlr4_runtime + PREFIX antlr4_runtime + GIT_REPOSITORY ${ANTLR4_GIT_REPOSITORY} + GIT_TAG ${ANTLR4_TAG} + DOWNLOAD_DIR ${CMAKE_CURRENT_BINARY_DIR} + BUILD_COMMAND "" + BUILD_IN_SOURCE 1 + SOURCE_DIR ${ANTLR4_ROOT} + SOURCE_SUBDIR runtime/Cpp + CMAKE_CACHE_ARGS + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + INSTALL_COMMAND "" + EXCLUDE_FROM_ALL 1) - # export generated cpp files into list - foreach(generated_file ${generated_files}) - list(APPEND antlr4cpp_src_files_${antlr4cpp_project_namespace} ${generated_file}) - if (NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - set_source_files_properties( - ${generated_file} - PROPERTIES - COMPILE_FLAGS -Wno-overloaded-virtual - ) - endif () - endforeach(generated_file) - message(STATUS "Antlr4Cpp ${antlr4cpp_project_namespace} Generated: ${generated_files}") +# Seperate build step as rarely people want both +ExternalProject_Add_Step( + antlr4_runtime + build_static + COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_static + # Depend on target instead of step (a custom command) + # to avoid running dependent steps concurrently + DEPENDS antlr4_runtime + BYPRODUCTS ${ANTLR4_STATIC_LIBRARIES} + EXCLUDE_FROM_MAIN 1 + WORKING_DIRECTORY ${ANTLR4_ROOT}) +ExternalProject_Add_StepTargets(antlr4_runtime build_static) - # export generated include directory - set(antlr4cpp_include_dirs_${antlr4cpp_project_namespace} ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}) - message(STATUS "Antlr4Cpp ${antlr4cpp_project_namespace} include: ${ANTLR4CPP_GENERATED_SRC_DIR}/${antlr4cpp_project_namespace}") +add_library(antlr4_static STATIC IMPORTED) +add_dependencies(antlr4_static antlr4_runtime-build_static) +set_target_properties(antlr4_static PROPERTIES + IMPORTED_LOCATION ${ANTLR4_STATIC_LIBRARIES}) -endmacro() +ExternalProject_Add_Step( + antlr4_runtime + build_shared + COMMAND ${ANTLR4_BUILD_COMMAND} antlr4_shared + # Depend on target instead of step (a custom command) + # to avoid running dependent steps concurrently + DEPENDS antlr4_runtime + BYPRODUCTS ${ANTLR4_SHARED_LIBRARIES} ${ANTLR4_RUNTIME_LIBRARIES} + EXCLUDE_FROM_MAIN 1 + WORKING_DIRECTORY ${ANTLR4_ROOT}) +ExternalProject_Add_StepTargets(antlr4_runtime build_shared) + +add_library(antlr4_shared SHARED IMPORTED) +add_dependencies(antlr4_shared antlr4_runtime-build_shared) +set_target_properties(antlr4_shared PROPERTIES + IMPORTED_LOCATION ${ANTLR4_RUNTIME_LIBRARIES}) +if(ANTLR4_SHARED_LIBRARIES) + set_target_properties(antlr4_shared PROPERTIES + IMPORTED_IMPLIB ${ANTLR4_SHARED_LIBRARIES}) +endif() diff --git a/runtime/Cpp/cmake/FindANTLR.cmake b/runtime/Cpp/cmake/FindANTLR.cmake new file mode 100644 index 000000000..50117cd02 --- /dev/null +++ b/runtime/Cpp/cmake/FindANTLR.cmake @@ -0,0 +1,124 @@ +find_package(Java QUIET COMPONENTS Runtime) + +if(NOT ANTLR_EXECUTABLE) + find_program(ANTLR_EXECUTABLE + NAMES antlr.jar antlr4.jar antlr-4.jar antlr-4.7.1-complete.jar) +endif() + +if(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE) + execute_process( + COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} + OUTPUT_VARIABLE ANTLR_COMMAND_OUTPUT + ERROR_VARIABLE ANTLR_COMMAND_ERROR + RESULT_VARIABLE ANTLR_COMMAND_RESULT + OUTPUT_STRIP_TRAILING_WHITESPACE) + + if(ANTLR_COMMAND_RESULT EQUAL 0) + string(REGEX MATCH "Version [0-9]+(\\.[0-9])*" ANTLR_VERSION ${ANTLR_COMMAND_OUTPUT}) + string(REPLACE "Version " "" ANTLR_VERSION ${ANTLR_VERSION}) + else() + message( + SEND_ERROR + "Command '${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE}' " + "failed with the output '${ANTLR_COMMAND_ERROR}'") + endif() + + macro(ANTLR_TARGET Name InputFile) + set(ANTLR_OPTIONS LEXER PARSER LISTENER VISITOR) + set(ANTLR_ONE_VALUE_ARGS PACKAGE OUTPUT_DIRECTORY DEPENDS_ANTLR) + set(ANTLR_MULTI_VALUE_ARGS COMPILE_FLAGS DEPENDS) + cmake_parse_arguments(ANTLR_TARGET + "${ANTLR_OPTIONS}" + "${ANTLR_ONE_VALUE_ARGS}" + "${ANTLR_MULTI_VALUE_ARGS}" + ${ARGN}) + + set(ANTLR_${Name}_INPUT ${InputFile}) + + if(ANTLR_TARGET_OUTPUT_DIRECTORY) + set(ANTLR_${Name}_OUTPUT_DIR ${ANTLR_TARGET_OUTPUT_DIRECTORY}) + else() + set(ANTLR_${Name}_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) + endif() + + unset(ANTLR_${Name}_CXX_OUTPUTS) + + # Get the shortest extension + string(REGEX REPLACE "\\.[^.]*$" "" ANTLR_INPUT ${InputFile}) + + if((ANTLR_TARGET_LEXER AND NOT ANTLR_TARGET_PARSER) OR + (ANTLR_TARGET_PARSER AND NOT ANTLR_TARGET_LEXER)) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.cpp) + set(ANTLR_${Name}_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.interp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}.tokens) + else() + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Parser.cpp) + list(APPEND ANTLR_${Name}_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.interp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Lexer.tokens) + endif() + + if(ANTLR_TARGET_LISTENER) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseListener.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Listener.cpp) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -listener) + endif() + + if(ANTLR_TARGET_VISITOR) + list(APPEND ANTLR_${Name}_CXX_OUTPUTS + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}BaseVisitor.cpp + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.h + ${ANTLR_${Name}_OUTPUT_DIR}/${ANTLR_INPUT}Visitor.cpp) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -visitor) + endif() + + if(ANTLR_TARGET_PACKAGE) + list(APPEND ANTLR_TARGET_COMPILE_FLAGS -package ${ANTLR_TARGET_PACKAGE}) + endif() + + list(APPEND ANTLR_${Name}_OUTPUTS ${ANTLR_${Name}_CXX_OUTPUTS}) + + if(ANTLR_TARGET_DEPENDS_ANTLR) + if(ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT) + list(APPEND ANTLR_TARGET_DEPENDS + ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_INPUT}) + list(APPEND ANTLR_TARGET_DEPENDS + ${ANTLR_${ANTLR_TARGET_DEPENDS_ANTLR}_OUTPUTS}) + else() + message(SEND_ERROR + "ANTLR target '${ANTLR_TARGET_DEPENDS_ANTLR}' not found") + endif() + endif() + + add_custom_command( + OUTPUT ${ANTLR_${Name}_OUTPUTS} + COMMAND ${Java_JAVA_EXECUTABLE} -jar ${ANTLR_EXECUTABLE} + ${InputFile} + -o ${ANTLR_${Name}_OUTPUT_DIR} + -no-listener + -Dlanguage=Cpp + ${ANTLR_TARGET_COMPILE_FLAGS} + DEPENDS ${InputFile} + ${ANTLR_TARGET_DEPENDS} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Building ${Name} with ANTLR ${ANTLR_VERSION}") + endmacro(ANTLR_TARGET) + +endif(ANTLR_EXECUTABLE AND Java_JAVA_EXECUTABLE) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + ANTLR + REQUIRED_VARS ANTLR_EXECUTABLE Java_JAVA_EXECUTABLE + VERSION_VAR ANTLR_VERSION) diff --git a/runtime/Cpp/cmake/README.md b/runtime/Cpp/cmake/README.md new file mode 100644 index 000000000..b88a6e83f --- /dev/null +++ b/runtime/Cpp/cmake/README.md @@ -0,0 +1,137 @@ +### Getting started with Antlr4cpp + +Here is how you can use this external project to create the antlr4cpp demo to start your project off. + +1. Create your project source folder somewhere. e.g. ~/srcfolder/ + 1. Make a subfolder cmake + 2. Copy the files in this folder to srcfolder/cmake + 3. Cut below and use it to create srcfolder/CMakeLists.txt + 4. Copy main.cpp, TLexer.g4 and TParser.g4 to ./srcfolder/ from [here](https://github.com/antlr/antlr4/tree/master/runtime/Cpp/demo) +2. Make a build folder e.g. ~/buildfolder/ +3. From the buildfolder, run `cmake ~/srcfolder; make` + +```cmake +# minimum required CMAKE version +CMAKE_MINIMUM_REQUIRED(VERSION 3.7 FATAL_ERROR) + +list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + +# compiler must be 11 or 14 +set(CMAKE_CXX_STANDARD 11) + +# required if linking to static library +add_definitions(-DANTLR4CPP_STATIC) + +# add external build for antlrcpp +include(ExternalAntlr4Cpp) +# add antrl4cpp artifacts to project environment +include_directories(${ANTLR4_INCLUDE_DIRS}) + +# set variable pointing to the antlr tool that supports C++ +# this is not required if the jar file can be found under PATH environment +set(ANTLR_EXECUTABLE /home/user/antlr-4.7.1-complete.jar) +# add macros to generate ANTLR Cpp code from grammar +find_package(ANTLR REQUIRED) + +# Call macro to add lexer and grammar to your build dependencies. +antlr_target(SampleGrammarLexer TLexer.g4 LEXER + PACKAGE antlrcpptest) +antlr_target(SampleGrammarParser TParser.g4 PARSER + PACKAGE antlrcpptest + DEPENDS_ANTLR SampleGrammarLexer) + +# include generated files in project environment +include_directories(${ANTLR_SampleGrammarLexer_OUTPUT_DIR}) +include_directories(${ANTLR_SampleGrammarParser_OUTPUT_DIR}) + +# add generated grammar to demo binary target +add_executable(demo main.cpp + ${ANTLR_SampleGrammarLexer_CXX_OUTPUTS} + ${ANTLR_SampleGrammarParser_CXX_OUTPUTS}) +target_link_libraries(demo antlr4_static) +``` + +--- +### Documentation for FindANTLR + +The module defines the following variables: +``` +ANTLR_FOUND - true is ANTLR jar executable is found +ANTLR_EXECUTABLE - the path to the ANTLR jar executable +ANTLR_VERSION - the version of ANTLR +``` + +If ANTLR is found, the module will provide the macros: +``` +ANTLR_TARGET( + [PACKAGE namespace] + [OUTPUT_DIRECTORY dir] + [DEPENDS_ANTLR ] + [COMPILE_FLAGS [args...]] + [DEPENDS [depends...]] + [LEXER] + [PARSER] + [LISTENER] + [VISITOR]) +``` +which creates a custom command to generate C++ files from ``. Running the macro defines the following variables: +``` +ANTLR_${name}_INPUT - the ANTLR input used for the macro +ANTLR_${name}_OUTPUTS - the outputs generated by ANTLR +ANTLR_${name}_CXX_OUTPUTS - the C++ outputs generated by ANTLR +ANTLR_${name}_OUTPUT_DIR - the output directory for ANTLR +``` + +The options are: +* `PACKAGE` - defines a namespace for the generated C++ files +* `OUTPUT_DIRECTORY` - the output directory for the generated files. By default it uses ${CMAKE_CURRENT_BINARY_DIR} +* `DEPENDS_ANTLR` - the dependent target generated from antlr_target for the current call +* `COMPILE_FLAGS` - additional compile flags for ANTLR tool +* `DEPENDS` - specify the files on which the command depends. It works the same way `DEPENDS` in [add_custom_command()](https://cmake.org/cmake/help/v3.11/command/add_custom_command.html) +* `LEXER` - specify the input file is a lexer grammar +* `PARSER` - specify the input file is a parser grammar +* `LISTENER` - tell ANTLR tool to generate a parse tree listener +* `VISITOR` - tell ANTLR tool to generate a parse tree visitor + +#### Examples +To generate C++ files from an ANTLR input file T.g4, which defines both lexer and parser grammar one may call: +```cmake +find_package(ANTLR REQUIRED) +antlr_target(Sample T.g4) +``` +do note that this command will do nothing unless the outputs of `Sample`, i.e. `ANTLR_Sample_CXX_OUTPUTS` gets used by some target. + +--- +### Documentation for ExternalAntlr4Cpp + +Including ExternalAntlr4Cpp will add `antlr4_static` and `antlr4_shared` as an optional target. It will also define the following variables: +``` +ANTLR4_INCLUDE_DIRS - the include directory that should be included when compiling C++ source file +ANTLR4_STATIC_LIBRARIES - path to antlr4 static library +ANTLR4_SHARED_LIBRARIES - path to antlr4 shared library +ANTLR4_RUNTIME_LIBRARIES - path to antlr4 shared runtime library (such as DLL and SO file) +ANTLR4_TAG - branch/tag used for building antlr4 library +``` +`ANTLR4_TAG` is set to master branch by default to keep antlr4 updated. However, it will be required to rebuild after every `clean` is called. Set `ANTLR4_TAG` to a desired commit hash value to avoid rebuilding after every `clean` and keep the build stable, at the cost of not automatically update to latest commit. + +#### Examples +To build and link ANTLR4 static library to a target one may call: +```cmake +include(ExternalAntlr4Cpp) +include_directories(${ANTLR4_INCLUDE_DIRS}) +add_executable(output main.cpp) +target_link_libraries(output antlr4_static) +``` + +It may also be a good idea to copy the runtime libraries (DLL or SO file) to the executable for it to run properly after build. i.e. To build and link antlr4 shared library to a target one may call: +```cmake +include(ExternalAntlr4Cpp) +include_directories(${ANTLR4_INCLUDE_DIRS}) +add_executable(output main.cpp) +target_link_libraries(output antlr4_shared) +add_custom_command(TARGET output + POST_BUILD + COMMAND ${CMAKE_COMMAND} + -E copy ${ANTLR4_RUNTIME_LIBRARIES} . + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) +```