From 66a949f26aacadea16b5785c6c1d4d88be97cfa3 Mon Sep 17 00:00:00 2001 From: humanoid2050 Date: Mon, 30 May 2022 15:19:53 -0400 Subject: [PATCH] reduced the number of duplicate operations between static and dynamic library creation, and added install cmake so this project can be included by other cmake projects --- cpp/CMakeLists.txt | 348 +++++++++++++++++++------------ cpp/cmake/ProjectConfig.cmake.in | 22 ++ 2 files changed, 241 insertions(+), 129 deletions(-) create mode 100644 cpp/cmake/ProjectConfig.cmake.in diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 14819cc..0215499 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -9,14 +9,19 @@ cmake_minimum_required (VERSION 3.10.2) project (bosdyn) +set(PACKAGE_VERSION_MAJOR 3) +set(PACKAGE_VERSION_MINOR 1) +set(PACKAGE_VERSION_PATCH 2) +set(PACKAGE_VERSION "${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}") + # Dependencies: -find_package(protobuf REQUIRED) -find_package(Eigen3 REQUIRED) -find_package(gRPC REQUIRED) -find_package(CLI11 REQUIRED) -include_directories(SYSTEM $) +find_package(Protobuf CONFIG REQUIRED) +find_package(Eigen3 CONFIG REQUIRED) +find_package(gRPC CONFIG REQUIRED) +find_package(CLI11 CONFIG REQUIRED) +find_package(Threads REQUIRED) + get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION) -include_directories(SYSTEM $) # Command-line arguments: set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE) @@ -27,172 +32,257 @@ IF (NOT UNIX) SET(BUILD_SHARED_LIBS OFF CACHE BOOL "Build using shared libraries" FORCE) ENDIF (NOT UNIX) +include(GNUInstallDirs) ### API protos LIBRARY ### -set(API_protos_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/protos/) -# Copy protos folders to build folder so they are in a subdirectory from the cpp folder (necessary for the proto cpp files generation). -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../protos/ DESTINATION ${API_protos_PATH}) +#find the proto files +set(API_protos_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../protos/) set(protos_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/protos) +file(MAKE_DIRECTORY ${protos_OUTPUT_DIR}) file(GLOB_RECURSE bosdyn_protos_files CONFIGURE_DEPENDS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${API_protos_PATH}/*.proto") -if (BUILD_SHARED_LIBS) - add_library(bosdyn_api ${bosdyn_protos_files}) - set_target_properties(bosdyn_api PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${protos_OUTPUT_DIR}) - target_link_libraries(bosdyn_api PUBLIC ${PROTOBUF_LIBRARIES} gRPC::grpc gRPC::grpc++) - target_include_directories(bosdyn_api PUBLIC - ${PROTOBUF_INCLUDE_DIRS} - ${protos_OUTPUT_DIR} - ) - protobuf_generate(TARGET bosdyn_api LANGUAGE cpp - IMPORT_DIRS ${API_protos_PATH} - PROTOC_OUT_DIR ${protos_OUTPUT_DIR}) - protobuf_generate(TARGET bosdyn_api - LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc - PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}" - IMPORT_DIRS ${API_protos_PATH} - PROTOC_OUT_DIR ${protos_OUTPUT_DIR} - ) - install(TARGETS bosdyn_api DESTINATION lib/) -endif() - -add_library(bosdyn_api_static STATIC ${bosdyn_protos_files}) -set_target_properties(bosdyn_api_static PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${protos_OUTPUT_DIR}) -target_link_libraries(bosdyn_api_static PUBLIC ${PROTOBUF_LIBRARIES} gRPC::grpc gRPC::grpc++) -target_include_directories(bosdyn_api_static PUBLIC - ${PROTOBUF_INCLUDE_DIRS} - ${protos_OUTPUT_DIR} +#only do the compilation once +add_library(bosdyn_api_obj OBJECT ${bosdyn_protos_files}) +set_property(TARGET bosdyn_api_obj PROPERTY POSITION_INDEPENDENT_CODE 1) +target_link_libraries(bosdyn_api_obj PUBLIC protobuf::libprotobuf gRPC::grpc gRPC::grpc++) +target_include_directories(bosdyn_api_obj PUBLIC + $ + $ ) -get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION) -protobuf_generate(TARGET bosdyn_api_static LANGUAGE cpp +protobuf_generate(TARGET bosdyn_api_obj LANGUAGE cpp IMPORT_DIRS ${API_protos_PATH} PROTOC_OUT_DIR ${protos_OUTPUT_DIR}) -protobuf_generate(TARGET bosdyn_api_static +protobuf_generate(TARGET bosdyn_api_obj LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}" IMPORT_DIRS ${API_protos_PATH} PROTOC_OUT_DIR ${protos_OUTPUT_DIR} ) -install(TARGETS bosdyn_api_static DESTINATION lib/) -install(DIRECTORY ${protos_OUTPUT_DIR}/bosdyn - DESTINATION include/api/protos/ +#set install params +install( + TARGETS bosdyn_api_obj + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +# actually make some libraries +if (BUILD_SHARED_LIBS) + add_library(bosdyn_api SHARED $) + target_link_libraries(bosdyn_api INTERFACE bosdyn_api_obj) + install( + TARGETS bosdyn_api + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) +endif() + +add_library(bosdyn_api_static STATIC $) +target_link_libraries(bosdyn_api_static INTERFACE bosdyn_api_obj) +install( + TARGETS bosdyn_api_static + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +# install the gnerated protobuf and grpc header files +install(DIRECTORY ${protos_OUTPUT_DIR}/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" ) -if (BUILD_CHOREOGRAPHY_LIBS) -### API choreography_protos LIBRARY ### -set(API_choreography_protos_PATH ${CMAKE_CURRENT_SOURCE_DIR}/build/choreography_protos/) -# Copy choreography_protos folders to build folder so they are in a subdirectory from the cpp folder (necessary for the proto cpp files generation). -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../choreography_protos/ DESTINATION ${API_choreography_protos_PATH}) -set(choreography_protos_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/choreography_protos) -file(GLOB_RECURSE bosdyn_choreography_protos_files CONFIGURE_DEPENDS - RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${API_choreography_protos_PATH}/*.proto") -if (BUILD_SHARED_LIBS) - add_library(bosdyn_choreography_protos ${bosdyn_choreography_protos_files}) - set_target_properties(bosdyn_choreography_protos PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${choreography_protos_OUTPUT_DIR}) - target_link_libraries(bosdyn_choreography_protos PUBLIC bosdyn_api) - target_include_directories(bosdyn_choreography_protos PUBLIC - ${PROTOBUF_INCLUDE_DIRS} - ${protos_OUTPUT_DIR} - ${choreography_protos_OUTPUT_DIR} +if (BUILD_CHOREOGRAPHY_LIBS) + ### API choreography_protos LIBRARY ### + #find the proto files + set(API_choreography_protos_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../choreography_protos/) + set(choreography_protos_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/choreography_protos) + file(MAKE_DIRECTORY ${choreography_protos_OUTPUT_DIR}) + file(GLOB_RECURSE bosdyn_choreography_protos_files CONFIGURE_DEPENDS + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${API_choreography_protos_PATH}/*.proto") + + #only do the compilation once + add_library(bosdyn_choreography_protos_obj OBJECT ${bosdyn_choreography_protos_files}) + set_property(TARGET bosdyn_choreography_protos_obj PROPERTY POSITION_INDEPENDENT_CODE 1) + target_link_libraries(bosdyn_choreography_protos_obj PUBLIC bosdyn_api) + target_include_directories(bosdyn_choreography_protos_obj PUBLIC + $ + $ ) - protobuf_generate(TARGET bosdyn_choreography_protos LANGUAGE cpp - IMPORT_DIRS ${API_choreography_protos_PATH} ${API_protos_PATH} + protobuf_generate(TARGET bosdyn_choreography_protos_obj LANGUAGE cpp + IMPORT_DIRS ${API_choreography_protos_PATH} ${API_protos_PATH} PROTOC_OUT_DIR ${choreography_protos_OUTPUT_DIR}) - protobuf_generate(TARGET bosdyn_choreography_protos + protobuf_generate(TARGET bosdyn_choreography_protos_obj LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}" - IMPORT_DIRS ${API_choreography_protos_PATH} ${API_protos_PATH} + IMPORT_DIRS ${API_choreography_protos_PATH} ${API_protos_PATH} PROTOC_OUT_DIR ${choreography_protos_OUTPUT_DIR} ) - install(TARGETS bosdyn_choreography_protos DESTINATION lib/) -endif() + #set install params + install( + TARGETS bosdyn_choreography_protos_obj + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) -add_library(bosdyn_choreography_protos_static STATIC ${bosdyn_choreography_protos_files}) -set_target_properties(bosdyn_choreography_protos_static PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${choreography_protos_OUTPUT_DIR}) -target_link_libraries(bosdyn_choreography_protos_static PUBLIC bosdyn_api) -target_include_directories(bosdyn_choreography_protos_static PUBLIC - ${PROTOBUF_INCLUDE_DIRS} - ${protos_OUTPUT_DIR} - ${choreography_protos_OUTPUT_DIR} -) -get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION) -protobuf_generate(TARGET bosdyn_choreography_protos_static LANGUAGE cpp - IMPORT_DIRS ${API_choreography_protos_PATH} ${API_protos_PATH} - PROTOC_OUT_DIR ${choreography_protos_OUTPUT_DIR}) -protobuf_generate(TARGET bosdyn_choreography_protos_static - LANGUAGE grpc GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc - PLUGIN "protoc-gen-grpc=${grpc_cpp_plugin_location}" - IMPORT_DIRS ${API_choreography_protos_PATH} ${API_protos_PATH} - PROTOC_OUT_DIR ${choreography_protos_OUTPUT_DIR} -) -install(TARGETS bosdyn_choreography_protos_static DESTINATION lib/) -install(DIRECTORY ${choreography_protos_OUTPUT_DIR}/bosdyn - DESTINATION include/api/choreography_protos/ - FILES_MATCHING PATTERN "*.h" -) + # actually make some libraries + if (BUILD_SHARED_LIBS) + add_library(bosdyn_choreography_protos SHARED $) + target_link_libraries(bosdyn_choreography_protos INTERFACE bosdyn_choreography_protos_obj) + install( + TARGETS bosdyn_choreography_protos + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + endif() + + add_library(bosdyn_choreography_protos_static STATIC $) + target_link_libraries(bosdyn_choreography_protos_static PUBLIC bosdyn_choreography_protos_obj) + install( + TARGETS bosdyn_choreography_protos_static + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + # install the gnerated protobuf and grpc header files + install(DIRECTORY ${choreography_protos_OUTPUT_DIR}/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" + ) endif() ### CLIENT LIBRARY ### -file(GLOB_RECURSE bosdyn_client_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/bosdyn/*") +file(GLOB_RECURSE bosdyn_client_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/bosdyn/*.cpp") +add_library (bosdyn_client_obj OBJECT ${bosdyn_client_SRC}) +set_property(TARGET bosdyn_client_obj PROPERTY POSITION_INDEPENDENT_CODE 1) +target_compile_features(bosdyn_client_obj PUBLIC cxx_std_14) +target_link_libraries(bosdyn_client_obj PUBLIC bosdyn_api Eigen3::Eigen) +target_include_directories(bosdyn_client_obj PUBLIC + $ + $ +) +#set install params +install( + TARGETS bosdyn_client_obj + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) +# actually make some libraries if (BUILD_SHARED_LIBS) - add_library (bosdyn_client SHARED ${bosdyn_client_SRC}) - target_compile_features(bosdyn_client PUBLIC cxx_std_14) - target_include_directories (bosdyn_client PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROTOBUF_INCLUDE_DIR} - ${EIGEN3_INCLUDE_DIR}) - target_link_libraries(bosdyn_client PUBLIC bosdyn_api) - install(TARGETS bosdyn_client DESTINATION lib/) + add_library (bosdyn_client SHARED $) + target_link_libraries(bosdyn_client PUBLIC bosdyn_client_obj bosdyn_client_obj) + install( + TARGETS bosdyn_client + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) endif() add_library (bosdyn_client_static STATIC ${bosdyn_client_SRC}) -target_compile_features(bosdyn_client_static PUBLIC cxx_std_14) -target_include_directories (bosdyn_client_static PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROTOBUF_INCLUDE_DIR} - ${EIGEN3_INCLUDE_DIR}) -target_link_libraries(bosdyn_client_static PUBLIC bosdyn_api_static) -install(TARGETS bosdyn_client_static DESTINATION lib/) +target_link_libraries(bosdyn_client_static PUBLIC bosdyn_client_obj bosdyn_api_static) +install( + TARGETS bosdyn_client_static + EXPORT ${PROJECT_NAME}Targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) -install(DIRECTORY libs/ DESTINATION include/bosdyn-client/ FILES_MATCHING PATTERN "*.h") +#extract the header files from the src dir and install them +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bosdyn + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" +) ### EXAMPLE EXECUTABLES ### -link_directories( - ${PROTOBUF_LIB_DIR} -) + add_executable(hello_spot ${CMAKE_CURRENT_SOURCE_DIR}/examples/hello_spot/hello_spot.cpp) target_compile_features(hello_spot PUBLIC cxx_std_14) -target_include_directories(hello_spot PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROTOBUF_INCLUDE_DIR} -) -target_link_libraries(hello_spot PUBLIC bosdyn_client_static) -install(TARGETS hello_spot DESTINATION bin/) +target_link_libraries(hello_spot PUBLIC bosdyn_client_static CLI11::CLI11) +install(TARGETS hello_spot RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + add_executable(spot_cam ${CMAKE_CURRENT_SOURCE_DIR}/examples/spot_cam/ptz_example.cpp) target_compile_features(spot_cam PUBLIC cxx_std_14) -target_include_directories(spot_cam PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROTOBUF_INCLUDE_DIR} -) -target_link_libraries(spot_cam PUBLIC bosdyn_client_static) -install(TARGETS spot_cam DESTINATION bin/) +target_link_libraries(spot_cam PUBLIC bosdyn_client_static CLI11::CLI11) +install(TARGETS spot_cam RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + add_executable(get_image ${CMAKE_CURRENT_SOURCE_DIR}/examples/get_image/get_image.cpp) target_compile_features(get_image PUBLIC cxx_std_14) -target_include_directories(get_image PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROTOBUF_INCLUDE_DIR} -) -target_link_libraries(get_image PUBLIC bosdyn_client_static) -install(TARGETS get_image DESTINATION bin/) +target_link_libraries(get_image PUBLIC bosdyn_client_static CLI11::CLI11) +install(TARGETS get_image RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + add_executable(basic_robot_command ${CMAKE_CURRENT_SOURCE_DIR}/examples/basic_robot_command/basic_robot_command.cpp) target_compile_features(basic_robot_command PUBLIC cxx_std_14) -target_include_directories(basic_robot_command PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR} - ${PROTOBUF_INCLUDE_DIR} +target_link_libraries(basic_robot_command PUBLIC bosdyn_client_static CLI11::CLI11) +install(TARGETS basic_robot_command RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) + + +# Save a version file in the project's binary directory +include(CMakePackageConfigHelpers) +set(VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake") +write_basic_package_version_file("${VERSION_FILE}" + VERSION ${PACKAGE_VERSION} + COMPATIBILITY AnyNewerVersion +) + +#this defines the instructions to generate a relocatable targets file at install time +set(PROJECT_CONFIG_PATH "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") +set(EXPORTS_FILE "UseInstall${PROJECT_NAME}.cmake") +install( + EXPORT ${PROJECT_NAME}Targets + NAMESPACE ${PROJECT_NAME}:: + FILE ${EXPORTS_FILE} + DESTINATION ${PROJECT_CONFIG_PATH} +) + +#this generates a relocatable config file for install, but it gets invoked at build time, +#so the output has to be saved in a way that won't conflict with the export config +set(CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}InstallConfig.cmake") + + +configure_package_config_file( "cmake/ProjectConfig.cmake.in" + ${CONFIG_FILE} + INSTALL_DESTINATION ${PROJECT_CONFIG_PATH} +) +#and because the config is a file in the build dir, it has to be installed explicitly +install( + FILES "${CONFIG_FILE}" + RENAME ${PROJECT_NAME}Config.cmake + DESTINATION "${PROJECT_CONFIG_PATH}" ) -target_link_libraries(basic_robot_command PUBLIC bosdyn_client_static) -install(TARGETS basic_robot_command DESTINATION bin/) + +option(ENABLE_EXPORT "Cause CMake to record this build so other projects can find it " ON) +if(ENABLE_EXPORT) + set(EXPORTS_FILE "UseExport${PROJECT_NAME}.cmake") + # Provide a targets script for the build dir + export(EXPORT ${PROJECT_NAME}Targets + NAMESPACE ${PROJECT_NAME}:: + FILE ${EXPORTS_FILE} + ) + + set(MAKE_PLUGIN_FILE "cmake/make_plugin.cmake") + set(MAKE_APP_FILE "cmake/make_standard_app.cmake") + #export requires a config.cmake to play well with find_package, so that gets made here + configure_package_config_file( "cmake/ProjectConfig.cmake.in" + ${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION ${CMAKE_CURRENT_BINARY_DIR} + INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR} + ) + + # Stick build location in the central CMake user package registry, so that + # it may be easily found. + message(STATUS "Location of this build will be exported. Set ENABLE_EXPORT to OFF if you don't want this and delete ~/.cmake/projects/${PROJECT_NAME} ") + export(PACKAGE ${PROJECT_NAME}) +endif() + + +return() \ No newline at end of file diff --git a/cpp/cmake/ProjectConfig.cmake.in b/cpp/cmake/ProjectConfig.cmake.in new file mode 100644 index 0000000..60f169b --- /dev/null +++ b/cpp/cmake/ProjectConfig.cmake.in @@ -0,0 +1,22 @@ +# Configuration file for @PROJECT_NAME@ library. +# Project specific variables are dynamically inserted + +@PACKAGE_INIT@ + +# Make sure the dependencies are available first +include(CMakeFindDependencyMacro) +find_dependency(Protobuf CONFIG REQUIRED) +find_dependency(Eigen3 CONFIG REQUIRED) +find_dependency(gRPC CONFIG REQUIRED) +find_dependency(CLI11 CONFIG REQUIRED) +find_dependency(Threads REQUIRED) + +# Pick up the auto-generated file which knows how to add the library targets +# This will mean that we don't have to supply full paths for the libraries +set(exports_file "${CMAKE_CURRENT_LIST_DIR}/@EXPORTS_FILE@") +if (EXISTS ${exports_file}) + message(STATUS "CMake is running ${exports_file}") + include(${exports_file}) +endif () + +check_required_components(@PROJECT_NAME@)