Improved ExternalAntlr4Cpp (Fixes #1872)

Removed the old macro antlr4cpp_process_grammar as it has a lot of
parameters which may not be what the user needs.
This commit is contained in:
Marcus Ong 2018-02-28 04:06:45 -06:00
parent 9551d12f7c
commit f296b75473
3 changed files with 363 additions and 210 deletions

View File

@ -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 <SOURCE_DIR>/scripts/CMakeLists.txt <SOURCE_DIR>"
# #--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 <SOURCE_DIR>/scripts/CMakeLists.txt <SOURCE_DIR>"
#--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=<INSTALL_DIR> -DCMAKE_SOURCE_DIR:PATH=<SOURCE_DIR>/runtime/Cpp <SOURCE_DIR>/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()

View File

@ -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)

137
runtime/Cpp/cmake/README.md Normal file
View File

@ -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(<name> <input>
[PACKAGE namespace]
[OUTPUT_DIRECTORY dir]
[DEPENDS_ANTLR <target>]
[COMPILE_FLAGS [args...]]
[DEPENDS [depends...]]
[LEXER]
[PARSER]
[LISTENER]
[VISITOR])
```
which creates a custom command to generate C++ files from `<input>`. 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})
```