diff --git a/AdsLib/CMakeLists.txt b/AdsLib/CMakeLists.txt index 4fbbaab3..ddeff4af 100644 --- a/AdsLib/CMakeLists.txt +++ b/AdsLib/CMakeLists.txt @@ -1,42 +1,168 @@ -set(SOURCES - AdsDef.cpp - AdsDevice.cpp - AdsFile.cpp - AdsLib.cpp - ECatAccess.cpp - Frame.cpp - LicenseAccess.cpp - Log.cpp - MasterDcStatAccess.cpp - RTimeAccess.cpp - RegistryAccess.cpp - RouterAccess.cpp - Sockets.cpp - SymbolAccess.cpp - - bhf/ParameterList.cpp - - standalone/AdsLib.cpp - standalone/AmsConnection.cpp - standalone/AmsNetId.cpp - standalone/AmsPort.cpp - standalone/AmsRouter.cpp - standalone/NotificationDispatcher.cpp -) - -add_library(ads ${SOURCES}) -add_library(ads::ads ALIAS ads) - -target_include_directories(ads PUBLIC $ -$) - -if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - target_link_libraries(ads PUBLIC wsock32) -endif() - - -if(WIN32 EQUAL 1) - target_link_libraries(ads PUBLIC ws2_32) -endif() - -target_link_libraries(ads PUBLIC Threads::Threads) +set(LIB_SOURCES + AdsDef.cpp + AdsDevice.cpp + AdsFile.cpp + AdsLib.cpp + ECatAccess.cpp + Frame.cpp + LicenseAccess.cpp + Log.cpp + MasterDcStatAccess.cpp + RTimeAccess.cpp + RegistryAccess.cpp + RouterAccess.cpp + Sockets.cpp + SymbolAccess.cpp +) +set(LIB_HEADERS + AdsDef.h + AdsDevice.h + AdsException.h + AdsFile.h + AdsLib.h + AdsNotification.h + AdsNotificationOOI.h + AdsVariable.h + AmsConnection.h + AmsHeader.h + AmsPort.h + AmsRouter.h + ECatAccess.h + Frame.h + LicenseAccess.h + Log.h + MasterDcStatAccess.h + NotificationDispatcher.h + RegistryAccess.h + RingBuffer.h + Router.h + RouterAccess.h + RTimeAccess.h + Semaphore.h + Sockets.h + SymbolAccess.h + wrap_socket.h + wrap_registry.h + wrap_endian.h +) + +set(BHF_SOURCES + bhf/ParameterList.cpp +) +set(BHF_HEADERS + bhf/ParameterList.h + bhf/StringToInteger.h + bhf/WindowsQuirks.h +) + +set(TWINCAT_SOURCES + TwinCAT/AdsLib.cpp +) +set(TWINCAT_HEADERS + TwinCAT/AdsDef.h + TwinCAT/AdsLib.h +) + +set(STANDALONE_SOURCES + standalone/AdsLib.cpp + standalone/AmsConnection.cpp + standalone/AmsNetId.cpp + standalone/AmsPort.cpp + standalone/AmsRouter.cpp + standalone/NotificationDispatcher.cpp +) +set(STANDALONE_HEADERS + standalone/AdsDef.h + standalone/AdsLib.h +) + +# Create the standalone variant +add_library(AdsLib) +target_sources(AdsLib PRIVATE + ${STANDALONE_SOURCES} + ${LIB_SOURCES} + ${BHF_SOURCES} +) +target_sources(AdsLib PUBLIC + FILE_SET HEADERS + FILES + ${LIB_HEADERS} + ${BHF_HEADERS} + ${STANDALONE_HEADERS} +) +target_include_directories(AdsLib PUBLIC + $ + $ +) + +target_link_libraries(AdsLib + PUBLIC + Threads::Threads +) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + target_link_libraries(AdsLib + PUBLIC + wsock32 + ws2_32 + ) +endif () + +if (BUILD_SHARED_LIBS) + target_compile_definitions(TcAdsLib + PUBLIC + BHF_ADS_EXPORT_C + BHF_ADS_USE_TWINCAT_ORDER + ) +endif () + +list(APPEND LIST_TARGETS_TO_INSTALL AdsLib) + +# Create the TwinCat variant. +if (TcAdsDll_FOUND AND NOT ONLY_STANDALONE) + add_library(TcAdsLib) + target_sources(TcAdsLib PRIVATE + ${TWINCAT_SOURCES} + ${LIB_SOURCES} + ${BHF_SOURCES} + ) + target_sources(TcAdsLib PUBLIC + FILE_SET HEADERS + FILES + ${LIB_HEADERS} + ${BHF_HEADERS} + ${TWINCAT_HEADERS} + ) + target_include_directories(TcAdsLib PUBLIC + $ + $ + ) + + target_link_libraries(TcAdsLib + PUBLIC + Threads::Threads + TcAdsDll::TcAdsDll + ) + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + target_link_libraries(TcAdsLib + PUBLIC + wsock32 + ws2_32 + ) + endif () + target_compile_definitions(TcAdsLib + PUBLIC + USE_TWINCAT_ROUTER + ) + if (BUILD_SHARED_LIBS) + target_compile_definitions(TcAdsLib + PUBLIC + BHF_ADS_EXPORT_C + ) + endif () + list(APPEND LIST_TARGETS_TO_INSTALL TcAdsLib) +endif () + +# Pass the created targets to the parent scope +set(LIST_TARGETS_TO_INSTALL "${LIST_TARGETS_TO_INSTALL}" PARENT_SCOPE) + diff --git a/AdsLibOOITest/CMakeLists.txt b/AdsLibOOITest/CMakeLists.txt new file mode 100644 index 00000000..e62e7a59 --- /dev/null +++ b/AdsLibOOITest/CMakeLists.txt @@ -0,0 +1,6 @@ +set(SOURCES + main.cpp +) + +add_executable(AdsLibOOITest ${SOURCES}) +target_link_libraries(AdsLibOOITest PRIVATE AdsLib Fructose) \ No newline at end of file diff --git a/AdsLibTest/CMakeLists.txt b/AdsLibTest/CMakeLists.txt index 2b9e5d0b..1adda7df 100644 --- a/AdsLibTest/CMakeLists.txt +++ b/AdsLibTest/CMakeLists.txt @@ -1,11 +1,6 @@ set(SOURCES - main.cpp + main.cpp ) -add_executable(AdsLibTest.bin ${SOURCES}) - -target_link_libraries(AdsLibTest.bin PUBLIC ads) - -target_include_directories(AdsLibTest.bin - PRIVATE ../tools/ -) +add_executable(AdsLibTest ${SOURCES}) +target_link_libraries(AdsLibTest PRIVATE AdsLib Fructose) diff --git a/AdsLibTestRef/CMakeLists.txt b/AdsLibTestRef/CMakeLists.txt new file mode 100644 index 00000000..247ad0c3 --- /dev/null +++ b/AdsLibTestRef/CMakeLists.txt @@ -0,0 +1,10 @@ +# Skip this tests if no TcAdsDll +if (NOT TcAdsDll_FOUND) + return() +endif () + +set(SOURCES + main.cpp +) +add_executable(TcAdsLibTestRef ${SOURCES}) +target_link_libraries(TcAdsLibTestRef PRIVATE TcAdsLib Fructose) \ No newline at end of file diff --git a/AdsTest/CMakeLists.txt b/AdsTest/CMakeLists.txt new file mode 100644 index 00000000..8933662b --- /dev/null +++ b/AdsTest/CMakeLists.txt @@ -0,0 +1,13 @@ +set(SOURCES + main.cpp + RegistryAccessTest.cpp + RegistryAccessTest.h +) + +add_executable(AdsTest ${SOURCES}) +target_link_libraries(AdsTest PRIVATE AdsLib) + +if(TcAdsDll_FOUND AND NOT ONLY_STANDALONE) + add_executable(TcAdsTest ${SOURCES}) + target_link_libraries(TcAdsTest PRIVATE TcAdsLib) +endif () diff --git a/AdsTool/CMakeLists.txt b/AdsTool/CMakeLists.txt index 7d4cad58..5feab914 100644 --- a/AdsTool/CMakeLists.txt +++ b/AdsTool/CMakeLists.txt @@ -1,2 +1,24 @@ -add_executable(AdsTool main.cpp) -target_link_libraries(AdsTool PUBLIC ads::ads) + +set(SOURCES + main.cpp +) +# Create the standalone variant +add_executable(AdsTool ${SOURCES}) +target_link_libraries(AdsTool PRIVATE AdsLib) +set_target_properties(AdsTool PROPERTIES + OUTPUT_NAME "adstool" +) +list(APPEND LIST_TARGETS_TO_INSTALL AdsTool) + +# Create the TwinCat variant +if (TcAdsDll_FOUND AND NOT ONLY_STANDALONE) + add_executable(TcAdsTool ${SOURCES}) + target_link_libraries(TcAdsTool PRIVATE TcAdsLib) + set_target_properties(TcAdsTool PROPERTIES + OUTPUT_NAME "tcadstool" + ) + list(APPEND LIST_TARGETS_TO_INSTALL TcAdsTool) +endif () + +# Pass the created targets to the parent scope +set(LIST_TARGETS_TO_INSTALL "${LIST_TARGETS_TO_INSTALL}" PARENT_SCOPE) \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index e340d9fc..5da5bc91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,76 +1,94 @@ -cmake_minimum_required(VERSION 3.13.0) - -project(ads) - -find_package(Threads) +cmake_minimum_required(VERSION 3.23.0) + +# Read the changelog file so that we can extract the version. +# The changelog has entries like 'adstool (113.0.33-1) trixie; urgency=medium' +file(READ "${CMAKE_SOURCE_DIR}/debian/changelog" CHANGELOG_CONTENT) +# Find the first instance of (VERSION-N)" and capture that string +string(REGEX MATCH "\\([0-9]+\\.[0-9]+\\.[0-9]+-[0-9]+\\)" VERSION_MATCH "${CHANGELOG_CONTENT}") +# Strip the surrounding parentheses and leave only the semantic version e.g., 113.0.33 +string(REGEX REPLACE "\\(([0-9]+\\.[0-9]+\\.[0-9]+)-[0-9]+\\)" "\\1" ADSLIB_VERSION "${VERSION_MATCH}") +# Do some checking to avoid issues. +if ("${ADSLIB_VERSION}" STREQUAL "") + message(FATAL_ERROR "Unable to extract AdsLib version from /debian/changelog") +endif () +message(STATUS "AdsLib Version: ${ADSLIB_VERSION}") +# We extend the CMake module path to add our own customized *.cmake +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH}) +project(ads VERSION ${ADSLIB_VERSION} LANGUAGES C CXX) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) - -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(COMPILE_OPTIONS - -pedantic - -Wall - -Wextra - ) - add_definitions(-D_GNU_SOURCE) -elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - # Compiler flags and definitions for Visual Studio come here -endif() - -add_definitions(-DCONFIG_DEFAULT_LOGLEVEL=1) -option(BUILD_SHARED_LIBS "Build using shared libraries" ON) - +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +if (BUILD_SHARED_LIBS AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + message(FATAL_ERROR "Shared library (.dll) not available in MSVC builds.") +endif () + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + add_compile_definitions(_GNU_SOURCE) +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + add_compile_definitions(NOMINMAX _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS) +endif () +add_compile_definitions(CONFIG_DEFAULT_LOGLEVEL=1) + +include(GNUInstallDirs) + +option(WITH_EXAMPLES "Build the examples (for the variant)" ON) +option(WITH_TESTS "Build the test (for the variant)" ON) +option(STANDALONE_ONLY "Build only the AdsLib as stand alone (no TwinCat TcAdsDll targets)" OFF) + +#Find the needed dependencies +find_package(Threads REQUIRED) +if (NOT STANDALONE_ONLY) + find_package(TcAdsDll) + if (NOT TcAdsDll_FOUND) + message(WARNING "Could NOT find TcAdsDll. TwinCat project targets will not be added.") + endif () +endif () +# This list variable will contain all the targets that are created and need to be install. +# It will be populated as the targets are declare on the cmake files. This is +# in order to deal with the possibility to create both targets if TcAdsDll is found. +set(LIST_TARGETS_TO_INSTALL) +# Add the source code. add_subdirectory(AdsLib) add_subdirectory(AdsTool) -add_subdirectory(AdsLibTest) -add_subdirectory(example) - - -# Install library -include(GenerateExportHeader) -set(ADSLIB_VERSION 0.0.20) - -set_property(TARGET ads PROPERTY VERSION ${ADSLIB_VERSION}) -set_property(TARGET ads PROPERTY SOVERSION 3) - - -# export library (either static or shared depending on BUILD_SHARED_LIBS) -install(TARGETS ads AdsTool - EXPORT adsTargets - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - INCLUDES DESTINATION include - ) - -install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/AdsLib/ DESTINATION include/ads/ - FILES_MATCHING PATTERN "*.hpp" PATTERN "*.h") - +if (WITH_EXAMPLES) + add_subdirectory(example) +endif () +if(WITH_TESTS) + include(UseFructose) + add_subdirectory(AdsLibTest) + add_subdirectory(AdsTest) + add_subdirectory(AdsLibTestRef) + add_subdirectory(AdsLibOOITest) +endif () + +# Create CMakeConfig . +message(STATUS "Available Targets: ${LIST_TARGETS_TO_INSTALL}") +install( + TARGETS ${LIST_TARGETS_TO_INSTALL} + EXPORT AdsConfig + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ads + FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ads +) -set(cmake_configfile_install lib/cmake/ads) -set(target_install_dest_name "${cmake_configfile_install}/adsTargets.cmake") +install(EXPORT AdsConfig + NAMESPACE Ads:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Ads +) include(CMakePackageConfigHelpers) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/adsConfigVersion.cmake" - VERSION ${ADSLIB_VERSION} - COMPATIBILITY AnyNewerVersion + "${CMAKE_CURRENT_BINARY_DIR}/AdsConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion ) -configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.cmake.in" - "${CMAKE_CURRENT_BINARY_DIR}/cmake/adsConfig.cmake" - INSTALL_DESTINATION "${cmake_configfile_install}" - PATH_VARS target_install_dest_name) - -install(EXPORT adsTargets - FILE adsTargets.cmake - NAMESPACE ads:: - DESTINATION "${cmake_configfile_install}" - EXPORT_LINK_INTERFACE_LIBRARIES) - -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/cmake/adsConfig.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/adsConfigVersion.cmake" - DESTINATION "${cmake_configfile_install}") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/AdsConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Ads +) diff --git a/cmake/FindTcAdsDll.cmake b/cmake/FindTcAdsDll.cmake new file mode 100644 index 00000000..ee44c0a0 --- /dev/null +++ b/cmake/FindTcAdsDll.cmake @@ -0,0 +1,119 @@ +# FindTcAdsDll.cmake — locate TcAdsDll (TwinCAT ADS DLL) library +# +# - Attempts to locate the ADS include directory and library file. +# - On success defines: +# TcAdsDll_FOUND +# TcAdsDll_INCLUDE_DIRS +# TcAdsDll_LIBRARIES +# +# Usage: +# find_package(TcAdsDll [REQUIRED]) +# if (TcAdsDll_FOUND) +# target_link_libraries(my_target PRIVATE TcAdsDll::TcAdsDll) +# endif() + +if (NOT TcAdsDll_FIND_QUIETLY) + message(STATUS "Looking for TcAdsDll (TwinCAT ADS-DLL)...") +endif () + +if (NOT WIN32) + message(WARNING "FindTcAdsDll.cmake only tested on WINDOWS") +endif () + +if (WIN32) + # Typical install locations on Windows + set(_TcAdsDll_PATH "$ENV{SystemDrive}/TwinCAT/AdsApi/TcAdsDll") +else () + # TODO: Linux not tested. Set additional known default locations to search. + set(_TcAdsDll_PATH) +endif () +# Find the include headers +find_path(TcAdsDll_INCLUDE_DIR + NAMES TcAdsApi.h TcAdsDef.h + PATHS "${_TcAdsDll_PATH}" + PATH_SUFFIXES "Include" "include" +) +# Find all related files base on the include files location. This is done +# assuming that the files are ordered as install by TwinCat. If they are +# in some other configuration this will not work. +if (WIN32) + cmake_path(GET TcAdsDll_INCLUDE_DIR PARENT_PATH TcAdsDll_ROOT_DIR) + if (NOT TcAdsDll_FIND_QUIETLY) + message(STATUS "Looking for TcAdsDll in ROOT ${TcAdsDll_ROOT_DIR}") + endif () + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + set(TcAdsDll_IMPLIB_DIR "${TcAdsDll_ROOT_DIR}/x64/lib") + set(TcAdsDll_DLL_DIR "${TcAdsDll_ROOT_DIR}/x64") + elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) + set(TcAdsDll_IMPLIB_DIR "${TcAdsDll_ROOT_DIR}/Lib") + set(TcAdsDll_DLL_DIR "${TcAdsDll_ROOT_DIR}") + endif () + # Use NO_DEFAULT_PATH so that we only look in the provided location. If not set + # the find_library will find the 32 bit version first regardless of the config + # which leads to errors. + find_library(TcAdsDll_IMPLIB + NAMES TcAdsDll + PATHS "${TcAdsDll_IMPLIB_DIR}" + NO_DEFAULT_PATH + ) + find_file(TcAdsDll_LIBRARY + NAMES TcAdsDll.dll + PATHS "${TcAdsDll_DLL_DIR}" + NO_DEFAULT_PATH + ) +else () + # TODO: Linux not tested. We just try to look for the library by name. + find_library(TcAdsDll_LIBRARY + NAMES TcAdsDll + ) +endif () + + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TcAdsDll + REQUIRED_VARS TcAdsDll_INCLUDE_DIR TcAdsDll_LIBRARY + VERSION_VAR TcAdsDll_VERSION +) + +if (NOT TcAdsDll_FOUND) + if (NOT TcAdsDll_FIND_QUIETLY) + message(WARNING "Could NOT find TcAdsDll. Try setting TcAdsDll_ROOT to the installation directory.") + endif () + return() +endif () + +set(TcAdsDll_INCLUDE_DIRS "${TcAdsDll_INCLUDE_DIR}") +set(TcAdsDll_LIBRARIES "${TcAdsDll_LIBRARY}") +if (WIN32) + list(APPEND TcAdsDll_LIBRARIES "${TcAdsDll_IMPLIB}" ) +endif () +set(TcAdsDll_FOUND "${TcAdsDll_FOUND}") + +mark_as_advanced(TcAdsDll_INCLUDE_DIR TcAdsDll_LIBRARY) + +# ---- Create imported target ------------------------------------------------- + +if (NOT TARGET TcAdsDll::TcAdsDll) + add_library(TcAdsDll::TcAdsDll SHARED IMPORTED) + if (WIN32) + set_target_properties(TcAdsDll::TcAdsDll PROPERTIES + IMPORTED_LOCATION "${TcAdsDll_LIBRARY}" + IMPORTED_IMPLIB "${TcAdsDll_IMPLIB}" + INTERFACE_INCLUDE_DIRECTORIES "${TcAdsDll_INCLUDE_DIR}" + ) + else () + set_target_properties(TcAdsDll::TcAdsDll PROPERTIES + IMPORTED_LOCATION "${TcAdsDll_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${TcAdsDll_INCLUDE_DIR}" + ) + endif () +endif () + +if (NOT TcAdsDll_FIND_QUIETLY) + message(STATUS "Found TcAdsDll (lib): ${TcAdsDll_LIBRARY}") + if (WIN32) + message(STATUS "Found TcAdsDll (implib): ${TcAdsDll_IMPLIB}") + endif () + message(STATUS "Found TcAdsDll (include): ${TcAdsDll_INCLUDE_DIR}") +endif () + diff --git a/cmake/UseFructose.cmake b/cmake/UseFructose.cmake new file mode 100644 index 00000000..c74862f0 --- /dev/null +++ b/cmake/UseFructose.cmake @@ -0,0 +1,7 @@ +include_guard(GLOBAL) + +# Find the Fructose copy inside the tools directory and set it as an imported target +add_library(Fructose INTERFACE) +target_include_directories(Fructose INTERFACE + ${CMAKE_SOURCE_DIR}/tools +) \ No newline at end of file diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index f402faf7..ab7e63da 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -2,6 +2,10 @@ set(SOURCES example.cpp ) -add_executable(example.bin ${SOURCES}) +add_executable(AdsExample ${SOURCES}) +target_link_libraries(AdsExample PRIVATE AdsLib) -target_link_libraries(example.bin PUBLIC ads) +if(TcAdsDll_FOUND AND NOT ONLY_STANDALONE) + add_executable(TcAdsExample ${SOURCES}) + target_link_libraries(TcAdsExample PRIVATE TcAdsLib) +endif ()