From c7d97d92ec6c36552d22b0becea982e13ad34d76 Mon Sep 17 00:00:00 2001 From: nre Date: Thu, 20 Apr 2017 11:36:49 +0200 Subject: [PATCH 1/9] Support building as a shared library On Windows, it is necessary to add some __declspec() calls to expose some symbols with different linkage types. This commit makes it possible for users to easily build cucumber-cpp either as a static or dynamic library by setting CUKE_ENABLE_SHARED_LIBS to ON or OFF at build time. --- CMakeLists.txt | 1 + .../cucumber-cpp/internal/ContextManager.hpp | 4 ++- .../cucumber-cpp/internal/CukeCommands.hpp | 3 +- include/cucumber-cpp/internal/CukeEngine.hpp | 15 +++++---- .../cucumber-cpp/internal/CukeEngineImpl.hpp | 3 +- include/cucumber-cpp/internal/Table.hpp | 4 ++- .../internal/connectors/wire/WireProtocol.hpp | 26 +++++++++------- .../internal/connectors/wire/WireServer.hpp | 7 +++-- .../internal/drivers/GTestDriver.hpp | 3 +- .../internal/hook/HookRegistrar.hpp | 31 ++++++++----------- include/cucumber-cpp/internal/hook/Tag.hpp | 7 +++-- .../internal/step/StepManager.hpp | 20 +++++------- src/CMakeLists.txt | 26 ++++++++++++++-- src/CukeEngine.cpp | 3 ++ 14 files changed, 91 insertions(+), 62 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 561b50dc..75585a17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.1) project(Cucumber-Cpp) +option(CUKE_ENABLE_SHARED_LIB "Generate a shared library" OFF) option(CUKE_USE_STATIC_BOOST "Statically link Boost (except boost::test)" ${WIN32}) option(CUKE_USE_STATIC_GTEST "Statically link Google Test" ON) option(CUKE_DISABLE_BOOST_TEST "Disable boost:test" OFF) diff --git a/include/cucumber-cpp/internal/ContextManager.hpp b/include/cucumber-cpp/internal/ContextManager.hpp index 62633256..72930804 100644 --- a/include/cucumber-cpp/internal/ContextManager.hpp +++ b/include/cucumber-cpp/internal/ContextManager.hpp @@ -1,6 +1,8 @@ #ifndef CUKE_CONTEXTMANAGER_HPP_ #define CUKE_CONTEXTMANAGER_HPP_ +#include "CukeExport.hpp" + #include #include @@ -13,7 +15,7 @@ namespace internal { typedef std::vector > contexts_type; -class ContextManager { +class CUCUMBER_CPP_EXPORT ContextManager { public: void purgeContexts(); template boost::weak_ptr addContext(); diff --git a/include/cucumber-cpp/internal/CukeCommands.hpp b/include/cucumber-cpp/internal/CukeCommands.hpp index 7721d056..e76a1f56 100644 --- a/include/cucumber-cpp/internal/CukeCommands.hpp +++ b/include/cucumber-cpp/internal/CukeCommands.hpp @@ -2,6 +2,7 @@ #define CUKE_CUKECOMMANDS_HPP_ #include "ContextManager.hpp" +#include "CukeExport.hpp" #include "Scenario.hpp" #include "Table.hpp" #include "step/StepManager.hpp" @@ -20,7 +21,7 @@ using boost::shared_ptr; /** * Legacy class to be removed when feature #31 is complete, substituted by CukeEngineImpl. */ -class CukeCommands { +class CUCUMBER_CPP_EXPORT CukeCommands { public: CukeCommands(); virtual ~CukeCommands(); diff --git a/include/cucumber-cpp/internal/CukeEngine.hpp b/include/cucumber-cpp/internal/CukeEngine.hpp index dc9b971e..1388135a 100644 --- a/include/cucumber-cpp/internal/CukeEngine.hpp +++ b/include/cucumber-cpp/internal/CukeEngine.hpp @@ -7,16 +7,18 @@ #include +#include "CukeExport.hpp" + namespace cucumber { namespace internal { -class StepMatchArg { +class CUCUMBER_CPP_EXPORT StepMatchArg { public: std::string value; std::ptrdiff_t position; }; -class StepMatch { +class CUCUMBER_CPP_EXPORT StepMatch { public: std::string id; std::vector args; @@ -24,7 +26,7 @@ class StepMatch { std::string regexp; }; -class InvokeException { +class CUCUMBER_CPP_EXPORT InvokeException { private: const std::string message; @@ -37,7 +39,7 @@ class InvokeException { virtual ~InvokeException() {} }; -class InvokeFailureException : public InvokeException { +class CUCUMBER_CPP_EXPORT InvokeFailureException : public InvokeException { private: const std::string exceptionType; @@ -48,7 +50,7 @@ class InvokeFailureException : public InvokeException { const std::string getExceptionType() const; }; -class PendingStepException : public InvokeException { +class CUCUMBER_CPP_EXPORT PendingStepException : public InvokeException { public: PendingStepException(const std::string & message); PendingStepException(const PendingStepException &rhs); @@ -96,7 +98,8 @@ class CukeEngine { */ virtual std::string snippetText(const std::string & keyword, const std::string & name, const std::string & multilineArgClass) const = 0; - virtual ~CukeEngine() {} + CUCUMBER_CPP_EXPORT CukeEngine(); + CUCUMBER_CPP_EXPORT virtual ~CukeEngine(); }; } diff --git a/include/cucumber-cpp/internal/CukeEngineImpl.hpp b/include/cucumber-cpp/internal/CukeEngineImpl.hpp index aaa67a9b..27a00c4e 100644 --- a/include/cucumber-cpp/internal/CukeEngineImpl.hpp +++ b/include/cucumber-cpp/internal/CukeEngineImpl.hpp @@ -2,6 +2,7 @@ #define CUKE_CUKEENGINE_IMPL_HPP_ #include "CukeEngine.hpp" +#include "CukeExport.hpp" #include "CukeCommands.hpp" namespace cucumber { @@ -13,7 +14,7 @@ namespace internal { * Currently it is a wrapper around CukeCommands. It will have its own * implementation when feature #31 is complete. */ -class CukeEngineImpl : public CukeEngine { +class CUCUMBER_CPP_EXPORT CukeEngineImpl : public CukeEngine { private: CukeCommands cukeCommands; diff --git a/include/cucumber-cpp/internal/Table.hpp b/include/cucumber-cpp/internal/Table.hpp index 9f6e9600..e4f5bab0 100644 --- a/include/cucumber-cpp/internal/Table.hpp +++ b/include/cucumber-cpp/internal/Table.hpp @@ -1,6 +1,8 @@ #ifndef CUKE_TABLE_HPP_ #define CUKE_TABLE_HPP_ +#include "CukeExport.hpp" + #include #include #include @@ -9,7 +11,7 @@ namespace cucumber { namespace internal { -class Table { +class CUCUMBER_CPP_EXPORT Table { private: typedef std::vector basic_type; public: diff --git a/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp b/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp index 6432d297..1412bfaf 100644 --- a/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp +++ b/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp @@ -1,8 +1,10 @@ #ifndef CUKE_WIREPROTOCOL_HPP_ #define CUKE_WIREPROTOCOL_HPP_ +#include "CukeExport.hpp" #include "ProtocolHandler.hpp" #include "../../CukeEngine.hpp" + #include namespace cucumber { @@ -14,7 +16,7 @@ namespace internal { class WireResponseVisitor; -class WireResponse { +class CUCUMBER_CPP_EXPORT WireResponse { public: WireResponse() {}; @@ -23,12 +25,12 @@ class WireResponse { virtual ~WireResponse() {}; }; -class SuccessResponse : public WireResponse { +class CUCUMBER_CPP_EXPORT SuccessResponse : public WireResponse { public: void accept(WireResponseVisitor& visitor) const; }; -class FailureResponse : public WireResponse { +class CUCUMBER_CPP_EXPORT FailureResponse : public WireResponse { private: const std::string message, exceptionType; @@ -41,7 +43,7 @@ class FailureResponse : public WireResponse { void accept(WireResponseVisitor& visitor) const; }; -class PendingResponse : public WireResponse { +class CUCUMBER_CPP_EXPORT PendingResponse : public WireResponse { private: const std::string message; @@ -53,7 +55,7 @@ class PendingResponse : public WireResponse { void accept(WireResponseVisitor& visitor) const; }; -class StepMatchesResponse : public WireResponse { +class CUCUMBER_CPP_EXPORT StepMatchesResponse : public WireResponse { private: const std::vector matchingSteps; @@ -64,7 +66,7 @@ class StepMatchesResponse : public WireResponse { void accept(WireResponseVisitor& visitor) const; }; -class SnippetTextResponse : public WireResponse { +class CUCUMBER_CPP_EXPORT SnippetTextResponse : public WireResponse { private: const std::string stepSnippet; @@ -76,7 +78,7 @@ class SnippetTextResponse : public WireResponse { void accept(WireResponseVisitor& visitor) const; }; -class WireResponseVisitor { +class CUCUMBER_CPP_EXPORT WireResponseVisitor { public: virtual void visit(const SuccessResponse& response) = 0; virtual void visit(const FailureResponse& response) = 0; @@ -91,7 +93,7 @@ class WireResponseVisitor { /** * Wire protocol request command. */ -class WireCommand { +class CUCUMBER_CPP_EXPORT WireCommand { public: /** * Runs the command on the provided engine @@ -105,7 +107,7 @@ class WireCommand { virtual ~WireCommand() {}; }; -class WireMessageCodecException : public std::exception { +class CUCUMBER_CPP_EXPORT WireMessageCodecException : public std::exception { private: const char *description; @@ -123,7 +125,7 @@ class WireMessageCodecException : public std::exception { /** * Transforms wire messages into commands and responses to messages. */ -class WireMessageCodec { +class CUCUMBER_CPP_EXPORT WireMessageCodec { public: /** * Decodes a wire message into a command. @@ -151,7 +153,7 @@ class WireMessageCodec { /** * WireMessageCodec implementation with JsonSpirit. */ -class JsonSpiritWireMessageCodec : public WireMessageCodec { +class CUCUMBER_CPP_EXPORT JsonSpiritWireMessageCodec : public WireMessageCodec { public: JsonSpiritWireMessageCodec(); boost::shared_ptr decode(const std::string &request) const; @@ -162,7 +164,7 @@ class JsonSpiritWireMessageCodec : public WireMessageCodec { * Wire protocol handler, delegating JSON encoding and decoding to a * codec object and running commands on a provided engine instance. */ -class WireProtocolHandler : public ProtocolHandler { +class CUCUMBER_CPP_EXPORT WireProtocolHandler : public ProtocolHandler { private: const WireMessageCodec& codec; CukeEngine& engine; diff --git a/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp b/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp index 5bbbdfbe..960aec77 100644 --- a/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp +++ b/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp @@ -1,6 +1,7 @@ #ifndef CUKE_WIRESERVER_HPP_ #define CUKE_WIRESERVER_HPP_ +#include "CukeExport.hpp" #include "ProtocolHandler.hpp" #include @@ -13,7 +14,7 @@ namespace internal { /** * Socket server that calls a protocol handler line by line */ -class SocketServer { +class CUCUMBER_CPP_EXPORT SocketServer { public: /** * Constructor for DI @@ -49,7 +50,7 @@ class SocketServer { /** * Socket server that calls a protocol handler line by line */ -class TCPSocketServer : public SocketServer { +class CUCUMBER_CPP_EXPORT TCPSocketServer : public SocketServer { public: /** * Type definition for TCP port @@ -90,7 +91,7 @@ class TCPSocketServer : public SocketServer { /** * Socket server that calls a protocol handler line by line */ -class UnixSocketServer : public SocketServer { +class CUCUMBER_CPP_EXPORT UnixSocketServer : public SocketServer { public: /** * Constructor for DI diff --git a/include/cucumber-cpp/internal/drivers/GTestDriver.hpp b/include/cucumber-cpp/internal/drivers/GTestDriver.hpp index 926c63ba..b6241fdd 100644 --- a/include/cucumber-cpp/internal/drivers/GTestDriver.hpp +++ b/include/cucumber-cpp/internal/drivers/GTestDriver.hpp @@ -1,6 +1,7 @@ #ifndef CUKE_GTESTDRIVER_HPP_ #define CUKE_GTESTDRIVER_HPP_ +#include "CukeExport.hpp" #include "../step/StepManager.hpp" #include @@ -8,7 +9,7 @@ namespace cucumber { namespace internal { -class GTestStep : public BasicStep { +class CUCUMBER_CPP_EXPORT GTestStep : public BasicStep { protected: const InvokeResult invokeStepBody(); diff --git a/include/cucumber-cpp/internal/hook/HookRegistrar.hpp b/include/cucumber-cpp/internal/hook/HookRegistrar.hpp index c065da87..cb86aacb 100644 --- a/include/cucumber-cpp/internal/hook/HookRegistrar.hpp +++ b/include/cucumber-cpp/internal/hook/HookRegistrar.hpp @@ -1,6 +1,7 @@ #ifndef CUKE_HOOKREGISTRAR_HPP_ #define CUKE_HOOKREGISTRAR_HPP_ +#include "CukeExport.hpp" #include "Tag.hpp" #include "../Scenario.hpp" #include "../step/StepManager.hpp" @@ -14,12 +15,12 @@ namespace cucumber { namespace internal { -class CallableStep { +class CUCUMBER_CPP_EXPORT CallableStep { public: virtual void call() = 0; }; -class Hook { +class CUCUMBER_CPP_EXPORT Hook { public: void setTags(const std::string &csvTagNotation); virtual void invokeHook(Scenario *scenario, CallableStep *step); @@ -36,10 +37,9 @@ class Hook { AndTagExpression tagExpression; }; -class BeforeHook : public Hook { -}; +class CUCUMBER_CPP_EXPORT BeforeHook : public Hook {}; -class AroundStepHook : public Hook { +class CUCUMBER_CPP_EXPORT AroundStepHook : public Hook { public: virtual void invokeHook(Scenario *scenario, CallableStep *step); virtual void skipHook(); @@ -47,24 +47,20 @@ class AroundStepHook : public Hook { CallableStep *step; }; -class AfterStepHook : public Hook { -}; +class CUCUMBER_CPP_EXPORT AfterStepHook : public Hook {}; -class AfterHook : public Hook { -}; +class CUCUMBER_CPP_EXPORT AfterHook : public Hook {}; -class UnconditionalHook : public Hook { +class CUCUMBER_CPP_EXPORT UnconditionalHook : public Hook { public: virtual void invokeHook(Scenario *scenario, CallableStep *step); }; -class BeforeAllHook : public UnconditionalHook { -}; +class CUCUMBER_CPP_EXPORT BeforeAllHook : public UnconditionalHook {}; -class AfterAllHook : public UnconditionalHook { -}; +class CUCUMBER_CPP_EXPORT AfterAllHook : public UnconditionalHook {}; -class HookRegistrar { +class CUCUMBER_CPP_EXPORT HookRegistrar { public: typedef std::list< boost::shared_ptr > hook_list_type; typedef std::list< boost::shared_ptr > aroundhook_list_type; @@ -107,8 +103,7 @@ class HookRegistrar { ; }; - -class StepCallChain { +class CUCUMBER_CPP_EXPORT StepCallChain { public: StepCallChain(Scenario *scenario, const StepInfo* stepInfo, const InvokeArgs *pStepArgs, HookRegistrar::aroundhook_list_type &aroundHooks); InvokeResult exec(); @@ -125,7 +120,7 @@ class StepCallChain { InvokeResult result; }; -class CallableStepChain : public CallableStep { +class CUCUMBER_CPP_EXPORT CallableStepChain : public CallableStep { public: CallableStepChain(StepCallChain *scc); void call(); diff --git a/include/cucumber-cpp/internal/hook/Tag.hpp b/include/cucumber-cpp/internal/hook/Tag.hpp index d74da418..a9394bf9 100644 --- a/include/cucumber-cpp/internal/hook/Tag.hpp +++ b/include/cucumber-cpp/internal/hook/Tag.hpp @@ -4,12 +4,13 @@ #include #include +#include "CukeExport.hpp" #include "../utils/Regex.hpp" namespace cucumber { namespace internal { -class TagExpression { +class CUCUMBER_CPP_EXPORT TagExpression { public: typedef std::vector tag_list; @@ -17,7 +18,7 @@ class TagExpression { virtual bool matches(const tag_list &tags) const = 0; }; -class OrTagExpression : public TagExpression { +class CUCUMBER_CPP_EXPORT OrTagExpression : public TagExpression { public: OrTagExpression(const std::string &csvTagNotation); bool matches(const tag_list &tags) const; @@ -30,7 +31,7 @@ class OrTagExpression : public TagExpression { static Regex & csvTagNotationRegex(); }; -class AndTagExpression : public TagExpression { +class CUCUMBER_CPP_EXPORT AndTagExpression : public TagExpression { public: AndTagExpression(); AndTagExpression(const std::string &csvTagNotation); diff --git a/include/cucumber-cpp/internal/step/StepManager.hpp b/include/cucumber-cpp/internal/step/StepManager.hpp index b93a7c6f..74bd1922 100644 --- a/include/cucumber-cpp/internal/step/StepManager.hpp +++ b/include/cucumber-cpp/internal/step/StepManager.hpp @@ -16,6 +16,7 @@ #include #endif +#include "CukeExport.hpp" #include "../Table.hpp" #include "../utils/IndexSequence.hpp" #include "../utils/Regex.hpp" @@ -27,7 +28,7 @@ typedef unsigned int step_id_type; class StepInfo; -class SingleStepMatch { +class CUCUMBER_CPP_EXPORT SingleStepMatch { public: typedef RegexMatch::submatches_type submatches_type; @@ -37,8 +38,7 @@ class SingleStepMatch { submatches_type submatches; }; - -class MatchResult { +class CUCUMBER_CPP_EXPORT MatchResult { public: typedef std::vector match_results_type; @@ -54,8 +54,7 @@ class MatchResult { match_results_type resultSet; }; - -class InvokeArgs { +class CUCUMBER_CPP_EXPORT InvokeArgs { typedef std::vector args_type; public: typedef args_type::size_type size_type; @@ -78,7 +77,7 @@ enum InvokeResultType { PENDING }; -class InvokeResult { +class CUCUMBER_CPP_EXPORT InvokeResult { private: InvokeResultType type; std::string description; @@ -100,8 +99,7 @@ class InvokeResult { const std::string &getDescription() const; }; - -class StepInfo : public boost::enable_shared_from_this { +class CUCUMBER_CPP_EXPORT StepInfo : public boost::enable_shared_from_this { public: StepInfo(const std::string &stepMatcher, const std::string source); SingleStepMatch matches(const std::string &stepDescription) const; @@ -115,8 +113,7 @@ class StepInfo : public boost::enable_shared_from_this { StepInfo& operator=(const StepInfo& other); }; - -class BasicStep { +class CUCUMBER_CPP_EXPORT BasicStep { public: InvokeResult invoke(const InvokeArgs *pArgs); @@ -174,8 +171,7 @@ class StepInvoker : public StepInfo { InvokeResult invokeStep(const InvokeArgs *args) const; }; - -class StepManager { +class CUCUMBER_CPP_EXPORT StepManager { protected: typedef std::map > steps_type; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4691cb2f..b8c85a54 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,5 @@ +include(GenerateExportHeader) + set(CUKE_SOURCES drivers/GenericDriver.cpp ContextManager.cpp @@ -41,14 +43,32 @@ if(CMAKE_EXTRA_GENERATOR OR MSVC_IDE) list(APPEND CUKE_SOURCES ${CUKE_HEADERS}) endif() -add_library(cucumber-cpp-nomain STATIC ${CUKE_SOURCES}) -add_library(cucumber-cpp STATIC ${CUKE_SOURCES} main.cpp) +if(CUKE_ENABLE_SHARED_LIB) + set(CUKE_LINKAGE SHARED) +else() + set(CUKE_LINKAGE STATIC) +endif() + +add_library(cucumber-cpp-nomain ${CUKE_LINKAGE} ${CUKE_SOURCES}) +add_library(cucumber-cpp ${CUKE_LINKAGE} ${CUKE_SOURCES} main.cpp) + +set_target_properties(cucumber-cpp cucumber-cpp-nomain PROPERTIES + DEFINE_SYMBOL cucumber_cpp_EXPORTS +) + +generate_export_header(cucumber-cpp + EXPORT_FILE_NAME "CukeExport.hpp" +) foreach(TARGET cucumber-cpp-nomain cucumber-cpp ) - target_include_directories(${TARGET} PUBLIC ${CMAKE_SOURCE_DIR}/include) + target_include_directories(${TARGET} + PUBLIC + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/include + ) target_link_libraries(${TARGET} PUBLIC Boost::boost diff --git a/src/CukeEngine.cpp b/src/CukeEngine.cpp index b9b52d7f..6d021f2d 100644 --- a/src/CukeEngine.cpp +++ b/src/CukeEngine.cpp @@ -39,5 +39,8 @@ PendingStepException::PendingStepException(const PendingStepException &rhs) : InvokeException(rhs) { } +CukeEngine::CukeEngine() {} + +CukeEngine::~CukeEngine() {} } } From 051503adccf9f972302b56e2e5c73fd75e332c81 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Fri, 18 May 2018 14:11:55 +0200 Subject: [PATCH 2/9] Place export header in same include dir namespace as other headers This makes it possible to install this header at some future point. --- include/cucumber-cpp/internal/ContextManager.hpp | 2 +- include/cucumber-cpp/internal/CukeCommands.hpp | 2 +- include/cucumber-cpp/internal/CukeEngine.hpp | 2 +- include/cucumber-cpp/internal/CukeEngineImpl.hpp | 2 +- include/cucumber-cpp/internal/Table.hpp | 2 +- include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp | 2 +- include/cucumber-cpp/internal/connectors/wire/WireServer.hpp | 2 +- include/cucumber-cpp/internal/drivers/GTestDriver.hpp | 2 +- include/cucumber-cpp/internal/hook/HookRegistrar.hpp | 2 +- include/cucumber-cpp/internal/hook/Tag.hpp | 2 +- include/cucumber-cpp/internal/step/StepManager.hpp | 2 +- src/CMakeLists.txt | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/cucumber-cpp/internal/ContextManager.hpp b/include/cucumber-cpp/internal/ContextManager.hpp index 72930804..154ca48d 100644 --- a/include/cucumber-cpp/internal/ContextManager.hpp +++ b/include/cucumber-cpp/internal/ContextManager.hpp @@ -1,7 +1,7 @@ #ifndef CUKE_CONTEXTMANAGER_HPP_ #define CUKE_CONTEXTMANAGER_HPP_ -#include "CukeExport.hpp" +#include #include diff --git a/include/cucumber-cpp/internal/CukeCommands.hpp b/include/cucumber-cpp/internal/CukeCommands.hpp index e76a1f56..994bba2d 100644 --- a/include/cucumber-cpp/internal/CukeCommands.hpp +++ b/include/cucumber-cpp/internal/CukeCommands.hpp @@ -2,7 +2,7 @@ #define CUKE_CUKECOMMANDS_HPP_ #include "ContextManager.hpp" -#include "CukeExport.hpp" +#include #include "Scenario.hpp" #include "Table.hpp" #include "step/StepManager.hpp" diff --git a/include/cucumber-cpp/internal/CukeEngine.hpp b/include/cucumber-cpp/internal/CukeEngine.hpp index 1388135a..9f5fa7f2 100644 --- a/include/cucumber-cpp/internal/CukeEngine.hpp +++ b/include/cucumber-cpp/internal/CukeEngine.hpp @@ -7,7 +7,7 @@ #include -#include "CukeExport.hpp" +#include namespace cucumber { namespace internal { diff --git a/include/cucumber-cpp/internal/CukeEngineImpl.hpp b/include/cucumber-cpp/internal/CukeEngineImpl.hpp index 27a00c4e..c53f736d 100644 --- a/include/cucumber-cpp/internal/CukeEngineImpl.hpp +++ b/include/cucumber-cpp/internal/CukeEngineImpl.hpp @@ -2,7 +2,7 @@ #define CUKE_CUKEENGINE_IMPL_HPP_ #include "CukeEngine.hpp" -#include "CukeExport.hpp" +#include #include "CukeCommands.hpp" namespace cucumber { diff --git a/include/cucumber-cpp/internal/Table.hpp b/include/cucumber-cpp/internal/Table.hpp index e4f5bab0..a7a70bdb 100644 --- a/include/cucumber-cpp/internal/Table.hpp +++ b/include/cucumber-cpp/internal/Table.hpp @@ -1,7 +1,7 @@ #ifndef CUKE_TABLE_HPP_ #define CUKE_TABLE_HPP_ -#include "CukeExport.hpp" +#include #include #include diff --git a/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp b/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp index 1412bfaf..9aec4d4e 100644 --- a/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp +++ b/include/cucumber-cpp/internal/connectors/wire/WireProtocol.hpp @@ -1,7 +1,7 @@ #ifndef CUKE_WIREPROTOCOL_HPP_ #define CUKE_WIREPROTOCOL_HPP_ -#include "CukeExport.hpp" +#include #include "ProtocolHandler.hpp" #include "../../CukeEngine.hpp" diff --git a/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp b/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp index 960aec77..78b32c9c 100644 --- a/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp +++ b/include/cucumber-cpp/internal/connectors/wire/WireServer.hpp @@ -1,7 +1,7 @@ #ifndef CUKE_WIRESERVER_HPP_ #define CUKE_WIRESERVER_HPP_ -#include "CukeExport.hpp" +#include #include "ProtocolHandler.hpp" #include diff --git a/include/cucumber-cpp/internal/drivers/GTestDriver.hpp b/include/cucumber-cpp/internal/drivers/GTestDriver.hpp index b6241fdd..7b4a3f24 100644 --- a/include/cucumber-cpp/internal/drivers/GTestDriver.hpp +++ b/include/cucumber-cpp/internal/drivers/GTestDriver.hpp @@ -1,7 +1,7 @@ #ifndef CUKE_GTESTDRIVER_HPP_ #define CUKE_GTESTDRIVER_HPP_ -#include "CukeExport.hpp" +#include #include "../step/StepManager.hpp" #include diff --git a/include/cucumber-cpp/internal/hook/HookRegistrar.hpp b/include/cucumber-cpp/internal/hook/HookRegistrar.hpp index cb86aacb..61d6a605 100644 --- a/include/cucumber-cpp/internal/hook/HookRegistrar.hpp +++ b/include/cucumber-cpp/internal/hook/HookRegistrar.hpp @@ -1,7 +1,7 @@ #ifndef CUKE_HOOKREGISTRAR_HPP_ #define CUKE_HOOKREGISTRAR_HPP_ -#include "CukeExport.hpp" +#include #include "Tag.hpp" #include "../Scenario.hpp" #include "../step/StepManager.hpp" diff --git a/include/cucumber-cpp/internal/hook/Tag.hpp b/include/cucumber-cpp/internal/hook/Tag.hpp index a9394bf9..d0855ac0 100644 --- a/include/cucumber-cpp/internal/hook/Tag.hpp +++ b/include/cucumber-cpp/internal/hook/Tag.hpp @@ -4,7 +4,7 @@ #include #include -#include "CukeExport.hpp" +#include #include "../utils/Regex.hpp" namespace cucumber { diff --git a/include/cucumber-cpp/internal/step/StepManager.hpp b/include/cucumber-cpp/internal/step/StepManager.hpp index 74bd1922..457ee899 100644 --- a/include/cucumber-cpp/internal/step/StepManager.hpp +++ b/include/cucumber-cpp/internal/step/StepManager.hpp @@ -16,7 +16,7 @@ #include #endif -#include "CukeExport.hpp" +#include #include "../Table.hpp" #include "../utils/IndexSequence.hpp" #include "../utils/Regex.hpp" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8c85a54..9064efcb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,7 +57,7 @@ set_target_properties(cucumber-cpp cucumber-cpp-nomain PROPERTIES ) generate_export_header(cucumber-cpp - EXPORT_FILE_NAME "CukeExport.hpp" + EXPORT_FILE_NAME "cucumber-cpp/internal/CukeExport.hpp" ) foreach(TARGET From c93b3b9b5dd19706947744f0b45f2f39b009ff42 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Fri, 18 May 2018 11:10:14 +0200 Subject: [PATCH 3/9] Use CMake standard variable BUILD_SHARED_LIBS Instead of the custom CUKE_ENABLE_SHARED_LIB option prefer the builtin BUILD_SHARED_LIBS option which controls the default library format for add_library. --- CMakeLists.txt | 2 +- examples/Calc/CMakeLists.txt | 2 +- examples/CalcQt/CMakeLists.txt | 2 +- src/CMakeLists.txt | 10 ++-------- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75585a17..b341e663 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.1) project(Cucumber-Cpp) -option(CUKE_ENABLE_SHARED_LIB "Generate a shared library" OFF) +option(BUILD_SHARED_LIBS "Generate shared libraries" OFF) option(CUKE_USE_STATIC_BOOST "Statically link Boost (except boost::test)" ${WIN32}) option(CUKE_USE_STATIC_GTEST "Statically link Google Test" ON) option(CUKE_DISABLE_BOOST_TEST "Disable boost:test" OFF) diff --git a/examples/Calc/CMakeLists.txt b/examples/Calc/CMakeLists.txt index 3641aec6..14f85f53 100644 --- a/examples/Calc/CMakeLists.txt +++ b/examples/Calc/CMakeLists.txt @@ -1,6 +1,6 @@ project(Calc) -add_library(Calc src/Calculator) +add_library(Calc STATIC src/Calculator) target_include_directories(Calc INTERFACE src) if(TARGET GTest::GTest) diff --git a/examples/CalcQt/CMakeLists.txt b/examples/CalcQt/CMakeLists.txt index 66139cee..1b3dd1a1 100644 --- a/examples/CalcQt/CMakeLists.txt +++ b/examples/CalcQt/CMakeLists.txt @@ -1,7 +1,7 @@ project(CalcQt) if(TARGET Qt::Core AND TARGET Qt::Gui AND TARGET Qt::Widgets AND TARGET Qt::Test) - add_library(libcalcqt src/CalculatorWidget.cpp src/CalculatorWidget.h) + add_library(libcalcqt STATIC src/CalculatorWidget.cpp src/CalculatorWidget.h) set_target_properties(libcalcqt PROPERTIES AUTOMOC ON) target_include_directories(libcalcqt INTERFACE src) target_link_libraries(libcalcqt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9064efcb..77a4bc26 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,14 +43,8 @@ if(CMAKE_EXTRA_GENERATOR OR MSVC_IDE) list(APPEND CUKE_SOURCES ${CUKE_HEADERS}) endif() -if(CUKE_ENABLE_SHARED_LIB) - set(CUKE_LINKAGE SHARED) -else() - set(CUKE_LINKAGE STATIC) -endif() - -add_library(cucumber-cpp-nomain ${CUKE_LINKAGE} ${CUKE_SOURCES}) -add_library(cucumber-cpp ${CUKE_LINKAGE} ${CUKE_SOURCES} main.cpp) +add_library(cucumber-cpp-nomain ${CUKE_SOURCES}) +add_library(cucumber-cpp ${CUKE_SOURCES} main.cpp) set_target_properties(cucumber-cpp cucumber-cpp-nomain PROPERTIES DEFINE_SYMBOL cucumber_cpp_EXPORTS From 5e5e7a87f9d45e5ab85e86d81e7949517bf383d5 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Fri, 18 May 2018 11:50:48 +0200 Subject: [PATCH 4/9] Link to (position independent) dependencies when building a shared lib Making sure GTest/GMock is built as position independent code is necessary when it's linked statically and we try to link it into Cucumber-CPP when that's built as a shared library. Furthermore Boost::unit_test_framework is a direct dependency of cucumber-cpp: we need to link to it when we use it. --- cmake/modules/FindGMock.cmake | 3 +++ src/CMakeLists.txt | 1 + 2 files changed, 4 insertions(+) diff --git a/cmake/modules/FindGMock.cmake b/cmake/modules/FindGMock.cmake index 4ca15de0..9920b1f3 100644 --- a/cmake/modules/FindGMock.cmake +++ b/cmake/modules/FindGMock.cmake @@ -260,6 +260,9 @@ if(NOT (${GMOCK_LIBRARY_EXISTS} AND ${GTEST_LIBRARY_EXISTS})) if(GTEST_USE_STATIC_LIBS) set(GTEST_CMAKE_ARGS -Dgtest_force_shared_crt:BOOL=ON -DBUILD_SHARED_LIBS=OFF) + if(BUILD_SHARED_LIBS) + list(APPEND GTEST_CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON) + endif() set(GTEST_LIBRARY_PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX}) else() set(GTEST_CMAKE_ARGS -DBUILD_SHARED_LIBS=ON) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 77a4bc26..bef9843c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ endif() if(TARGET Boost::unit_test_framework) list(APPEND CUKE_EXTRA_PRIVATE_LIBRARIES Boost::unit_test_framework) list(APPEND CUKE_SOURCES drivers/BoostDriver.cpp) + list(APPEND CUKE_DEP_LIBRARIES ${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}) endif() if(TARGET Qt::Test) From 3405988e59ae0d9486eee31613f5fe7223e63c9c Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Fri, 18 May 2018 14:00:50 +0200 Subject: [PATCH 5/9] Export all test drivers Instead of only exporting the GTestDriver, make sure they're all exported from SHARED libraries. --- include/cucumber-cpp/internal/drivers/BoostDriver.hpp | 3 ++- include/cucumber-cpp/internal/drivers/GenericDriver.hpp | 3 ++- include/cucumber-cpp/internal/drivers/QtTestDriver.hpp | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/cucumber-cpp/internal/drivers/BoostDriver.hpp b/include/cucumber-cpp/internal/drivers/BoostDriver.hpp index 387a4427..8482ebcc 100644 --- a/include/cucumber-cpp/internal/drivers/BoostDriver.hpp +++ b/include/cucumber-cpp/internal/drivers/BoostDriver.hpp @@ -2,13 +2,14 @@ #define CUKE_BOOSTDRIVER_HPP_ #include "../step/StepManager.hpp" +#include namespace cucumber { namespace internal { class CukeBoostLogInterceptor; -class BoostStep : public BasicStep { +class CUCUMBER_CPP_EXPORT BoostStep : public BasicStep { protected: const InvokeResult invokeStepBody(); diff --git a/include/cucumber-cpp/internal/drivers/GenericDriver.hpp b/include/cucumber-cpp/internal/drivers/GenericDriver.hpp index 32e99283..e7fc7e20 100644 --- a/include/cucumber-cpp/internal/drivers/GenericDriver.hpp +++ b/include/cucumber-cpp/internal/drivers/GenericDriver.hpp @@ -2,11 +2,12 @@ #define CUKE_GENERICDRIVER_HPP_ #include "../step/StepManager.hpp" +#include namespace cucumber { namespace internal { -class GenericStep : public BasicStep { +class CUCUMBER_CPP_EXPORT GenericStep : public BasicStep { protected: virtual const InvokeResult invokeStepBody(); }; diff --git a/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp b/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp index 94e3ab22..ca433a7c 100644 --- a/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp +++ b/include/cucumber-cpp/internal/drivers/QtTestDriver.hpp @@ -2,12 +2,13 @@ #define CUKE_QTTESTDRIVER_HPP_ #include "../step/StepManager.hpp" +#include #include namespace cucumber { namespace internal { -class QtTestStep : public BasicStep { +class CUCUMBER_CPP_EXPORT QtTestStep : public BasicStep { friend class QtTestObject; public: From 3eef825d71fd97b2223756b5b7e7d21d7485c579 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Fri, 18 May 2018 14:19:49 +0200 Subject: [PATCH 6/9] Export main() from SHARED library Otherwise how can we execute anything? --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 35af8308..226696e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -39,7 +40,7 @@ void acceptWireProtocol(const std::string& host, int port, const std::string& un } -int main(int argc, char **argv) { +int CUCUMBER_CPP_EXPORT main(int argc, char** argv) { using boost::program_options::value; boost::program_options::options_description optionDescription("Allowed options"); optionDescription.add_options() From 4c3b0cc27d6db58ba594503cb4e14e150768f151 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Fri, 18 May 2018 17:16:56 +0200 Subject: [PATCH 7/9] Hide all symbols by default This prevents unmarked symbols, which we consider to be internals, from being available on the dynamic library's dynamic symbol table (EXPORT table on Windows). Furthermore we split out a static library. This allows us to expose the library internals to unit tests only, through this static library. This works because symbol hiding only affects dynamic linking, not static linking. --- CMakeLists.txt | 5 +++++ src/CMakeLists.txt | 19 +++++++++++++++++-- tests/CMakeLists.txt | 4 ++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b341e663..a282cc27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,10 @@ cmake_minimum_required(VERSION 3.1) +if(NOT CMAKE_VERSION VERSION_LESS "3.3") + # Don't ignore visibility related properties for non-SHARED targets + cmake_policy(SET CMP0063 NEW) +endif() + project(Cucumber-Cpp) option(BUILD_SHARED_LIBS "Generate shared libraries" OFF) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bef9843c..8b842654 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -44,11 +44,20 @@ if(CMAKE_EXTRA_GENERATOR OR MSVC_IDE) list(APPEND CUKE_SOURCES ${CUKE_HEADERS}) endif() +# Library for unit tests relying on internals +add_library(cucumber-cpp-internal STATIC ${CUKE_SOURCES}) + add_library(cucumber-cpp-nomain ${CUKE_SOURCES}) add_library(cucumber-cpp ${CUKE_SOURCES} main.cpp) -set_target_properties(cucumber-cpp cucumber-cpp-nomain PROPERTIES - DEFINE_SYMBOL cucumber_cpp_EXPORTS +set_target_properties( + cucumber-cpp-internal + cucumber-cpp + cucumber-cpp-nomain + PROPERTIES + DEFINE_SYMBOL cucumber_cpp_EXPORTS + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON ) generate_export_header(cucumber-cpp @@ -56,6 +65,7 @@ generate_export_header(cucumber-cpp ) foreach(TARGET + cucumber-cpp-internal cucumber-cpp-nomain cucumber-cpp ) @@ -75,6 +85,11 @@ foreach(TARGET json_spirit.header ${CUKE_EXTRA_PRIVATE_LIBRARIES} ) + # Don't export or import symbols for statically linked libraries + get_property(type TARGET ${TARGET} PROPERTY TYPE) + if(NOT "${type}" MATCHES "^(SHARED|MODULE)_LIBRARY$") + target_compile_definitions(${TARGET} PUBLIC CUCUMBER_CPP_STATIC_DEFINE) + endif() if(MINGW) target_link_libraries(${TARGET} PRIVATE diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a51e736e..f1335081 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,7 +2,7 @@ function(cuke_add_driver_test TEST_FILE) get_filename_component(TEST_NAME ${TEST_FILE} NAME) message(STATUS "Adding " ${TEST_NAME}) add_executable(${TEST_NAME} ${TEST_FILE}.cpp) - target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-nomain ${ARGN}) + target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-internal ${ARGN}) add_test(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) endfunction() @@ -11,7 +11,7 @@ if(TARGET GMock::Main) get_filename_component(TEST_NAME ${TEST_FILE} NAME) message(STATUS "Adding " ${TEST_NAME}) add_executable(${TEST_NAME} ${TEST_FILE}.cpp) - target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-nomain ${ARGN} GMock::Main) + target_link_libraries(${TEST_NAME} PRIVATE cucumber-cpp-internal ${ARGN} GMock::Main) gtest_add_tests(${TEST_NAME} "" ${TEST_FILE}.cpp) # Run all tests in executable at once too. This ensures that the used fixtures get tested # properly too. Additionally gather the output in jUnit compatible output for CI. From bd1f9b25459191e30fe7a9eef6e85d5ce006c394 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Sat, 19 May 2018 13:30:25 +0200 Subject: [PATCH 8/9] Hide GMock/GTest internals from cucumber-cpp dynamic symbol table --- cmake/modules/FindGMock.cmake | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindGMock.cmake b/cmake/modules/FindGMock.cmake index 9920b1f3..8d732424 100644 --- a/cmake/modules/FindGMock.cmake +++ b/cmake/modules/FindGMock.cmake @@ -261,7 +261,13 @@ if(NOT (${GMOCK_LIBRARY_EXISTS} AND ${GTEST_LIBRARY_EXISTS})) if(GTEST_USE_STATIC_LIBS) set(GTEST_CMAKE_ARGS -Dgtest_force_shared_crt:BOOL=ON -DBUILD_SHARED_LIBS=OFF) if(BUILD_SHARED_LIBS) - list(APPEND GTEST_CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON) + list(APPEND GTEST_CMAKE_ARGS + -DCMAKE_POSITION_INDEPENDENT_CODE=ON + -Dgtest_hide_internal_symbols=ON + -DCMAKE_CXX_VISIBILITY_PRESET=hidden + -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON + -DCMAKE_POLICY_DEFAULT_CMP0063=NEW + ) endif() set(GTEST_LIBRARY_PREFIX ${CMAKE_STATIC_LIBRARY_PREFIX}) else() From 9fe13ae4543833b6594fa20d2904070c20956676 Mon Sep 17 00:00:00 2001 From: Giel van Schijndel Date: Sat, 19 May 2018 13:45:20 +0200 Subject: [PATCH 9/9] Build as shared library on CI Because this will catch errors with APIs not being properly marked for export. AFAIK this shouldn't fail to catch any errors that a static build would, so I'm not retaining the static build. --- CMakeLists.txt | 2 ++ appveyor.yml | 2 +- travis.sh | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a282cc27..01fff601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -317,6 +317,8 @@ else() ${ARGN} ${CUKE_FEATURES_DIR} ${USES_TERMINAL} + # Execute in same directory as where DLLs appear on Windows + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/src ) endfunction(add_feature_target) diff --git a/appveyor.yml b/appveyor.yml index 443d315d..0d1ce95e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -41,7 +41,7 @@ install: build_script: - cmake -E make_directory build -- cmake -E chdir build cmake -G "%CMAKE_GENERATOR%" -DCUKE_ENABLE_EXAMPLES=ON -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_INCLUDEDIR="%BOOST_INCLUDEDIR%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" -DCMAKE_PREFIX_PATH="%QT_DIR%" .. +- cmake -E chdir build cmake -G "%CMAKE_GENERATOR%" -DCUKE_ENABLE_EXAMPLES=ON -DBUILD_SHARED_LIBS=ON -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_INCLUDEDIR="%BOOST_INCLUDEDIR%" -DBOOST_LIBRARYDIR="%BOOST_LIBRARYDIR%" -DCMAKE_PREFIX_PATH="%QT_DIR%" .. - cmake --build build test_script: diff --git a/travis.sh b/travis.sh index cc139602..840bf7f4 100755 --- a/travis.sh +++ b/travis.sh @@ -57,6 +57,7 @@ cmake -E make_directory build cmake -E chdir build cmake \ -G Ninja \ -DCUKE_ENABLE_EXAMPLES=on \ + -DBUILD_SHARED_LIBS=ON \ ${CMAKE_PREFIX_PATH:+"-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}"} \ ${COVERALLS_SERVICE_NAME:+"-DCMAKE_BUILD_TYPE=Debug"} \ ${COVERALLS_SERVICE_NAME:+"-DCMAKE_CXX_FLAGS='--coverage'"} \