带有单独 TU 的 x3 链接器错误
x3 linker error with separate TU
随着我的解析器的增长,我将一些规则分成不同的翻译单元 (TU),并且链接器问题出现了。在数周的尝试和错误都没有成功之后,我将我的 ~50 条规则减少到(希望如此)这里介绍的最小示例。我已经阅读了相关的 并进行了检查,我在上下文 typedef iso8859_1::space_type
中使用了它,并且稍后调用了 iso8859_1::space
。另外我不让编译器推断 iterator_type.
我通过替换一些东西使链接器错误更有趣:
In function `bool x3::rule<parser::string_literal_class, ast::string_literal, false>::parse<std::string::const_iterator, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> >, x3::variant<ast::string_literal> >(std::string::const_iterator&, std::string::const_iterator const&, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> > const&, x3::unused_type, x3::variant<ast::string_literal>&) const':
main.cpp: .text._ZNK5boost6spirit2x34ruleIN6parser20string_literal_classEN3ast14string_literalELb0EE5parseIN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS1_7contextINS1_17error_handler_tagEKSt17reference_wrapperINS1_13error_handlerISJ_EEENSK_INS1_11skipper_tagEKNS1_10char_classINS0_13char_encoding9iso8859_1ENS1_9space_tagEEENS1_11unused_typeEEEEENS1_7variantIJS6_EEEEEbRT_RKS13_RKT0_SY_RT1_[_ZNK5boost6spirit2x34ruleIN6parser20string_literal_classEN3ast14string_literalELb0EE5parseIN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS1_7contextINS1_17error_handler_tagEKSt17reference_wrapperINS1_13error_handlerISJ_EEENSK_INS1_11skipper_tagEKNS1_10char_classINS0_13char_encoding9iso8859_1ENS1_9space_tagEEENS1_11unused_typeEEEEENS1_7variantIJS6_EEEEEbRT_RKS13_RKT0_SY_RT1_]+0x37): undefined reference to `bool parser::parse_rule<std::string::const_iterator, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> >, x3::variant<ast::string_literal> >(x3::rule<parser::string_literal_class, ast::string_literal, false>, std::string::const_iterator&, std::string::const_iterator const&, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> > const&, x3::variant<ast::string_literal>&)'
__gnu_cxx17
迭代器(来自 libstdc++??)让我很恼火。我确实尝试了 g++7.1.0,结果相同。
附加文件以使用 CMake 文件重现链接器错误(使用选项 LINKER_ERROR 获取或什至不获取(没有 TU 的单体构建))。
ast.hpp
#ifndef AST_HPP_
#define AST_HPP_
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <string>
#include <boost/fusion/include/adapt_struct.hpp>
namespace ast {
namespace x3 = boost::spirit::x3;
struct string_literal {
std::string literal;
};
using primary = x3::variant<string_literal>;
using factor = x3::variant<primary>;
}
BOOST_FUSION_ADAPT_STRUCT(ast::string_literal,
literal
)
#endif // AST_HPP_
grammar_def.hpp
#include "ast.hpp"
#include <boost/spirit/home/x3.hpp>
#if defined(LINKER_ERROR)
#include "literal.hpp"
#endif
namespace parser {
namespace x3 = boost::spirit::x3;
struct factor_class;
struct primary_class;
#if !defined(LINKER_ERROR)
struct string_literal_class;
#endif
typedef x3::rule<factor_class, ast::factor> factor_type;
typedef x3::rule<primary_class, ast::primary> primary_type;
#if !defined(LINKER_ERROR)
typedef x3::rule<string_literal_class, ast::string_literal> string_literal_type;
#endif
factor_type const factor{ "factor" };
primary_type const primary{ "primary" };
#if !defined(LINKER_ERROR)
string_literal_type const string_literal{ "string_literal" };
#endif
#if defined(LINKER_ERROR)
namespace {
auto const& string_literal = parser_api::string_literal();
}
#endif
auto const factor_def = primary;
auto const primary_def = string_literal;
#if !defined(LINKER_ERROR)
auto const string_literal_def =
x3::lexeme ['"' >> *x3::char_ >> '"' ]
;
#endif
BOOST_SPIRIT_DEFINE(factor, primary)
#if !defined(LINKER_ERROR)
BOOST_SPIRIT_DEFINE(
string_literal
)
#endif
}
literal_def.hpp
#ifndef PARSER_LITERAL_DEF_HPP_
#define PARSER_LITERAL_DEF_HPP_
#include "literal.hpp"
namespace parser {
namespace x3 = boost::spirit::x3;
string_literal_type const string_literal { "string_literal" };
auto const string_literal_def =
x3::lexeme ['"' >> *x3::char_ >> '"' ];
BOOST_SPIRIT_DEFINE(
string_literal
)
}
namespace parser_api {
parser::string_literal_type const& string_literal()
{
return parser::string_literal;
}
}
#endif /* PARSER_LITERAL_DEF_HPP_ */
literal.cpp
#include "literal_def.hpp"
#include "parser_config.hpp"
namespace parser {
namespace x3 = boost::spirit::x3;
BOOST_SPIRIT_INSTANTIATE(
string_literal_type,
iterator_type,
context_type
);
}
literal.hpp
#ifndef PARSER_LITERAL_HPP_
#define PARSER_LITERAL_HPP_
#include "ast.hpp"
#include <boost/spirit/home/x3.hpp>
namespace parser {
namespace x3 = boost::spirit::x3;
struct string_literal_class;
typedef x3::rule<string_literal_class, ast::string_literal> string_literal_type;
BOOST_SPIRIT_DECLARE(string_literal_type);
}
namespace parser_api {
parser::string_literal_type const& string_literal();
}
#endif /* PARSER_LITERAL_HPP_ */
main.cpp
#include "grammar_def.hpp"
#include "parser_config.hpp"
#include <iostream>
int main()
{
namespace x3 = boost::spirit::x3;
ast::factor attr;
std::string input{ "a * b" };
parser::iterator_type iter = input.begin();
parser::iterator_type const end = input.end();
parser::error_handler_type error_handler(iter, end, std::cerr);
auto const parser =
x3::with<x3::error_handler_tag>(std::ref(error_handler))
[
parser::factor
];
bool success = x3::phrase_parse(iter, end, parser, x3::iso8859_1::space, attr);
return 0;
}
parser_config.hpp
#ifndef PARSER_CONFIG_HPP_
#define PARSER_CONFIG_HPP_
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/utility/error_reporting.hpp>
namespace parser {
namespace x3 = boost::spirit::x3;
template <typename Iterator>
using error_handler = x3::error_handler<Iterator>;
using error_handler_tag = x3::error_handler_tag;
typedef std::string::const_iterator iterator_type;
typedef error_handler<iterator_type> error_handler_type;
typedef x3::phrase_parse_context<
x3::iso8859_1::space_type>::type phrase_context_type;
typedef x3::with_context<
error_handler_tag
, std::reference_wrapper<error_handler_type> const
, phrase_context_type
>::type context_type;
}
#endif /* CONFIG_HPP_ */
最后是 CMakeLists.txt
cmake_minimum_required(VERSION 3.6)
project(x3_linker_error LANGUAGES CXX)
find_package(Boost REQUIRED COMPONENTS system)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# lib
add_library(${PROJECT_NAME}_x3 STATIC
literal.cpp
)
# exe
add_executable(${PROJECT_NAME}
main.cpp
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
${PROJECT_NAME}_x3
${Boost_SYSTEM_LIBRARY}
)
set(CMAKE_VERBOSE_MAKEFILE ON)
option(LINKER_ERROR "Enforce the linker error" ON)
if(LINKER_ERROR)
message("## Build to show linker errors")
target_compile_definitions(${PROJECT_NAME}_x3 PRIVATE LINKER_ERROR)
target_compile_definitions(${PROJECT_NAME} PRIVATE LINKER_ERROR)
endif()
代码也在 wandbox。
将 parser_api::string_literal() 设置到实例文件 literal.cpp 中也不会改变结果(正如预期的那样)。希望这不是我的愚蠢错误,但几周后我就结束了...
附录
我还测试了 Joel de Guzman 的提示,将 int x = context_type{};
插入 literal.cpp 和 main.cpp 以获取使用的上下文 - 两者相同:
x3_linker_error/literal.cpp
'boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, const std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::iso8859_1, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type> >::context(<brace-enclosed initializer list>)'
x3_linker_error/main.cpp
'boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, const std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::iso8859_1, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type> >::context(<brace-enclosed initializer list>)'
在 Larry Evans 的帮助下,问题已解决。详情请关注spirit-general mailing list.
这样的代码片段是正确的。似乎这个问题确实出现在另一个上下文中,如 Linking error when changing > to >> 之前几次,并由 Seth 讨论过。
解决方法是use/cloneLarry的get_rhs branch of spirit.x3
git clone --branch get_rhs https://github.com/cppljevans/spirit.git destination
并使用定义的 BOOST_ERROR_CODE_HEADER_ONLY
进行编译。 Boost 1.64 的 Spirit.X3 无法编译。我修改了 CMake 文件以反映更改(并克隆到 cppljevans)并添加了 Larry 的编译日志所见的进一步定义:
cmake_minimum_required(VERSION 3.6)
project(x3_linker_error LANGUAGES CXX)
find_package(Boost REQUIRED COMPONENTS system)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# lib
add_library(${PROJECT_NAME}_x3 STATIC
literal.cpp
)
target_include_directories(${PROJECT_NAME}_x3
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cppljevans/include
)
target_compile_definitions(${PROJECT_NAME}_x3 PRIVATE
BOOST_SPIRIT_GET_RHS_CRTP=1 BOOST_SPIRIT_ATTR_XFORM_IN_RULE=1
)
# exe
add_executable(${PROJECT_NAME}
main.cpp
)
target_include_directories(${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cppljevans/include
)
target_compile_definitions(${PROJECT_NAME} PRIVATE
BOOST_SPIRIT_GET_RHS_CRTP=1 BOOST_SPIRIT_ATTR_XFORM_IN_RULE=1
BOOST_ERROR_CODE_HEADER_ONLY
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
${PROJECT_NAME}_x3
${Boost_SYSTEM_LIBRARY}
)
set(CMAKE_VERBOSE_MAKEFILE ON)
option(LINKER_ERROR "Enforce the linker error" ON)
if(LINKER_ERROR)
message("## Build to show linker errors")
target_compile_definitions(${PROJECT_NAME}_x3 PRIVATE LINKER_ERROR)
target_compile_definitions(${PROJECT_NAME} PRIVATE LINKER_ERROR)
endif()
随着我的解析器的增长,我将一些规则分成不同的翻译单元 (TU),并且链接器问题出现了。在数周的尝试和错误都没有成功之后,我将我的 ~50 条规则减少到(希望如此)这里介绍的最小示例。我已经阅读了相关的 iso8859_1::space_type
中使用了它,并且稍后调用了 iso8859_1::space
。另外我不让编译器推断 iterator_type.
我通过替换一些东西使链接器错误更有趣:
In function `bool x3::rule<parser::string_literal_class, ast::string_literal, false>::parse<std::string::const_iterator, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> >, x3::variant<ast::string_literal> >(std::string::const_iterator&, std::string::const_iterator const&, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> > const&, x3::unused_type, x3::variant<ast::string_literal>&) const':
main.cpp: .text._ZNK5boost6spirit2x34ruleIN6parser20string_literal_classEN3ast14string_literalELb0EE5parseIN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS1_7contextINS1_17error_handler_tagEKSt17reference_wrapperINS1_13error_handlerISJ_EEENSK_INS1_11skipper_tagEKNS1_10char_classINS0_13char_encoding9iso8859_1ENS1_9space_tagEEENS1_11unused_typeEEEEENS1_7variantIJS6_EEEEEbRT_RKS13_RKT0_SY_RT1_[_ZNK5boost6spirit2x34ruleIN6parser20string_literal_classEN3ast14string_literalELb0EE5parseIN9__gnu_cxx17__normal_iteratorIPKcNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEEEENS1_7contextINS1_17error_handler_tagEKSt17reference_wrapperINS1_13error_handlerISJ_EEENSK_INS1_11skipper_tagEKNS1_10char_classINS0_13char_encoding9iso8859_1ENS1_9space_tagEEENS1_11unused_typeEEEEENS1_7variantIJS6_EEEEEbRT_RKS13_RKT0_SY_RT1_]+0x37): undefined reference to `bool parser::parse_rule<std::string::const_iterator, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> >, x3::variant<ast::string_literal> >(x3::rule<parser::string_literal_class, ast::string_literal, false>, std::string::const_iterator&, std::string::const_iterator const&, x3::context<x3::error_handler_tag, std::reference_wrapper<x3::error_handler<std::string::const_iterator > > const, x3::context<x3::skipper_tag, x3::char_class<char_encoding::iso8859_1, x3::space_tag> const, x3::unused_type> > const&, x3::variant<ast::string_literal>&)'
__gnu_cxx17
迭代器(来自 libstdc++??)让我很恼火。我确实尝试了 g++7.1.0,结果相同。
附加文件以使用 CMake 文件重现链接器错误(使用选项 LINKER_ERROR 获取或什至不获取(没有 TU 的单体构建))。
ast.hpp
#ifndef AST_HPP_
#define AST_HPP_
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <string>
#include <boost/fusion/include/adapt_struct.hpp>
namespace ast {
namespace x3 = boost::spirit::x3;
struct string_literal {
std::string literal;
};
using primary = x3::variant<string_literal>;
using factor = x3::variant<primary>;
}
BOOST_FUSION_ADAPT_STRUCT(ast::string_literal,
literal
)
#endif // AST_HPP_
grammar_def.hpp
#include "ast.hpp"
#include <boost/spirit/home/x3.hpp>
#if defined(LINKER_ERROR)
#include "literal.hpp"
#endif
namespace parser {
namespace x3 = boost::spirit::x3;
struct factor_class;
struct primary_class;
#if !defined(LINKER_ERROR)
struct string_literal_class;
#endif
typedef x3::rule<factor_class, ast::factor> factor_type;
typedef x3::rule<primary_class, ast::primary> primary_type;
#if !defined(LINKER_ERROR)
typedef x3::rule<string_literal_class, ast::string_literal> string_literal_type;
#endif
factor_type const factor{ "factor" };
primary_type const primary{ "primary" };
#if !defined(LINKER_ERROR)
string_literal_type const string_literal{ "string_literal" };
#endif
#if defined(LINKER_ERROR)
namespace {
auto const& string_literal = parser_api::string_literal();
}
#endif
auto const factor_def = primary;
auto const primary_def = string_literal;
#if !defined(LINKER_ERROR)
auto const string_literal_def =
x3::lexeme ['"' >> *x3::char_ >> '"' ]
;
#endif
BOOST_SPIRIT_DEFINE(factor, primary)
#if !defined(LINKER_ERROR)
BOOST_SPIRIT_DEFINE(
string_literal
)
#endif
}
literal_def.hpp
#ifndef PARSER_LITERAL_DEF_HPP_
#define PARSER_LITERAL_DEF_HPP_
#include "literal.hpp"
namespace parser {
namespace x3 = boost::spirit::x3;
string_literal_type const string_literal { "string_literal" };
auto const string_literal_def =
x3::lexeme ['"' >> *x3::char_ >> '"' ];
BOOST_SPIRIT_DEFINE(
string_literal
)
}
namespace parser_api {
parser::string_literal_type const& string_literal()
{
return parser::string_literal;
}
}
#endif /* PARSER_LITERAL_DEF_HPP_ */
literal.cpp
#include "literal_def.hpp"
#include "parser_config.hpp"
namespace parser {
namespace x3 = boost::spirit::x3;
BOOST_SPIRIT_INSTANTIATE(
string_literal_type,
iterator_type,
context_type
);
}
literal.hpp
#ifndef PARSER_LITERAL_HPP_
#define PARSER_LITERAL_HPP_
#include "ast.hpp"
#include <boost/spirit/home/x3.hpp>
namespace parser {
namespace x3 = boost::spirit::x3;
struct string_literal_class;
typedef x3::rule<string_literal_class, ast::string_literal> string_literal_type;
BOOST_SPIRIT_DECLARE(string_literal_type);
}
namespace parser_api {
parser::string_literal_type const& string_literal();
}
#endif /* PARSER_LITERAL_HPP_ */
main.cpp
#include "grammar_def.hpp"
#include "parser_config.hpp"
#include <iostream>
int main()
{
namespace x3 = boost::spirit::x3;
ast::factor attr;
std::string input{ "a * b" };
parser::iterator_type iter = input.begin();
parser::iterator_type const end = input.end();
parser::error_handler_type error_handler(iter, end, std::cerr);
auto const parser =
x3::with<x3::error_handler_tag>(std::ref(error_handler))
[
parser::factor
];
bool success = x3::phrase_parse(iter, end, parser, x3::iso8859_1::space, attr);
return 0;
}
parser_config.hpp
#ifndef PARSER_CONFIG_HPP_
#define PARSER_CONFIG_HPP_
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/utility/error_reporting.hpp>
namespace parser {
namespace x3 = boost::spirit::x3;
template <typename Iterator>
using error_handler = x3::error_handler<Iterator>;
using error_handler_tag = x3::error_handler_tag;
typedef std::string::const_iterator iterator_type;
typedef error_handler<iterator_type> error_handler_type;
typedef x3::phrase_parse_context<
x3::iso8859_1::space_type>::type phrase_context_type;
typedef x3::with_context<
error_handler_tag
, std::reference_wrapper<error_handler_type> const
, phrase_context_type
>::type context_type;
}
#endif /* CONFIG_HPP_ */
最后是 CMakeLists.txt
cmake_minimum_required(VERSION 3.6)
project(x3_linker_error LANGUAGES CXX)
find_package(Boost REQUIRED COMPONENTS system)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# lib
add_library(${PROJECT_NAME}_x3 STATIC
literal.cpp
)
# exe
add_executable(${PROJECT_NAME}
main.cpp
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
${PROJECT_NAME}_x3
${Boost_SYSTEM_LIBRARY}
)
set(CMAKE_VERBOSE_MAKEFILE ON)
option(LINKER_ERROR "Enforce the linker error" ON)
if(LINKER_ERROR)
message("## Build to show linker errors")
target_compile_definitions(${PROJECT_NAME}_x3 PRIVATE LINKER_ERROR)
target_compile_definitions(${PROJECT_NAME} PRIVATE LINKER_ERROR)
endif()
代码也在 wandbox。
将 parser_api::string_literal() 设置到实例文件 literal.cpp 中也不会改变结果(正如预期的那样)。希望这不是我的愚蠢错误,但几周后我就结束了...
附录
我还测试了 Joel de Guzman 的提示,将 int x = context_type{};
插入 literal.cpp 和 main.cpp 以获取使用的上下文 - 两者相同:
x3_linker_error/literal.cpp
'boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, const std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::iso8859_1, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type> >::context(<brace-enclosed initializer list>)'
x3_linker_error/main.cpp
'boost::spirit::x3::context<boost::spirit::x3::error_handler_tag, const std::reference_wrapper<boost::spirit::x3::error_handler<__gnu_cxx::__normal_iterator<const char*, std::__cxx11::basic_string<char> > > >, boost::spirit::x3::context<boost::spirit::x3::skipper_tag, const boost::spirit::x3::char_class<boost::spirit::char_encoding::iso8859_1, boost::spirit::x3::space_tag>, boost::spirit::x3::unused_type> >::context(<brace-enclosed initializer list>)'
在 Larry Evans 的帮助下,问题已解决。详情请关注spirit-general mailing list.
这样的代码片段是正确的。似乎这个问题确实出现在另一个上下文中,如 Linking error when changing > to >> 之前几次,并由 Seth 讨论过。
解决方法是use/cloneLarry的get_rhs branch of spirit.x3
git clone --branch get_rhs https://github.com/cppljevans/spirit.git destination
并使用定义的 BOOST_ERROR_CODE_HEADER_ONLY
进行编译。 Boost 1.64 的 Spirit.X3 无法编译。我修改了 CMake 文件以反映更改(并克隆到 cppljevans)并添加了 Larry 的编译日志所见的进一步定义:
cmake_minimum_required(VERSION 3.6)
project(x3_linker_error LANGUAGES CXX)
find_package(Boost REQUIRED COMPONENTS system)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# lib
add_library(${PROJECT_NAME}_x3 STATIC
literal.cpp
)
target_include_directories(${PROJECT_NAME}_x3
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cppljevans/include
)
target_compile_definitions(${PROJECT_NAME}_x3 PRIVATE
BOOST_SPIRIT_GET_RHS_CRTP=1 BOOST_SPIRIT_ATTR_XFORM_IN_RULE=1
)
# exe
add_executable(${PROJECT_NAME}
main.cpp
)
target_include_directories(${PROJECT_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/cppljevans/include
)
target_compile_definitions(${PROJECT_NAME} PRIVATE
BOOST_SPIRIT_GET_RHS_CRTP=1 BOOST_SPIRIT_ATTR_XFORM_IN_RULE=1
BOOST_ERROR_CODE_HEADER_ONLY
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
${PROJECT_NAME}_x3
${Boost_SYSTEM_LIBRARY}
)
set(CMAKE_VERBOSE_MAKEFILE ON)
option(LINKER_ERROR "Enforce the linker error" ON)
if(LINKER_ERROR)
message("## Build to show linker errors")
target_compile_definitions(${PROJECT_NAME}_x3 PRIVATE LINKER_ERROR)
target_compile_definitions(${PROJECT_NAME} PRIVATE LINKER_ERROR)
endif()