diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index 335f057..c9457c8 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -45,33 +45,33 @@ jobs: - name: Build main target shell: bash run: | - cmake --build cmake-build-release --target QtCMake + cmake --build cmake-build-release --target QtBoostCMake - name: Run program shell: bash working-directory: ./cmake-build-release/bin run: | if [ "$RUNNER_OS" == "Windows" ]; then - ./QtCMake.exe --help + ./QtBoostCMake.exe --help else - ./QtCMake --help + ./QtBoostCMake --help fi - name: Build tests shell: bash run: | if [ "$RUNNER_OS" == "Windows" ]; then - cmake --build ./cmake-build-release --target QtCMake_tests || echo "Built with errors" + cmake --build ./cmake-build-release --target QtBoostCMake_tests || echo "Built with errors" else - cmake --build ./cmake-build-release --target QtCMake_tests + cmake --build ./cmake-build-release --target QtBoostCMake_tests fi - name: Run tests shell: bash working-directory: ./cmake-build-release/tests run: | if [ "$RUNNER_OS" == "Windows" ]; then - ./QtCMake_tests.exe || echo "Tests failed" # Due to a specific MinGW-related Github Actions issue + ./QtBoostCMake_tests.exe || echo "Tests failed" # Due to a specific MinGW-related Github Actions issue else - ./QtCMake_tests + ./QtBoostCMake_tests fi style-check: @@ -158,11 +158,12 @@ jobs: sudo apt-get update # Install a C++23-capable toolchain and clang-tidy-19 for better C++23 support sudo apt-get -y install clang-19 clang-tidy-19 - - name: Install Qt dependencies for Linux + - name: Install Qt and Boost run: | sudo apt update sudo apt install libgl1-mesa-dev libglu1-mesa-dev sudo apt install qt6-base-dev + sudo apt install libboost-all-dev - name: Create CMake cache run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index d87281f..086bef0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ cmake_minimum_required(VERSION 3.25) project( - QtCMake - VERSION 1.1.0 - DESCRIPTION "CMake project for easy Qt connection to other CMake projects" + QtBoostCMake + VERSION 1.0.0 + DESCRIPTION "CMake project for easy Qt and Boost connection to other CMake projects" LANGUAGES CXX ) @@ -29,7 +29,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") set(CMAKE_CXX_FLAGS_DEBUG "/MDd") set(CMAKE_CXX_FLAGS_RELEASE "/O2") else () - set(CMAKE_CXX_FLAGS_DEBUG "-g") + set(CMAKE_CXX_FLAGS_DEBUG "-g -O0") set(CMAKE_CXX_FLAGS_RELEASE "-O3") if (WIN32) set(CMAKE_CXX_STANDARD_LIBRARIES "-static-libgcc -static-libstdc++ -lwsock32 -lws2_32 ${CMAKE_CXX_STANDARD_LIBRARIES}") diff --git a/README.md b/README.md index 75a89b3..1e76db7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ -# QtCMake -A C++ project template with Qt6 and CMake that downloads and compiles Qt. -The resulting app is an executable that can be run on a system without Qt. +# QtBoostCMake + +A C++ project template with Qt6, Boost, Google Tests and CMake that downloads and compiles Qt and Boost. +The resulting app is an executable that can be run on a system without Qt and Boost. The main Qt6 configuration is found in the [correspondent](lib/qt/CMakeLists.txt) CMakeLists.txt file. +The main Boost configuration is found in the [correspondent](lib/boost/CMakeLists.txt) CMakeLists.txt file. +The main Google Tests configuration is found in the [correspondent](tests/CMakeLists.txt) CMakeLists.txt file. > Note that statically compiled Qt6 weights more than 5 GB. > The good thing is that user does not need whole compiled Qt6 with this configuration. diff --git a/bin/CMakeLists.txt b/bin/CMakeLists.txt index f5ab6be..1fec6bd 100644 --- a/bin/CMakeLists.txt +++ b/bin/CMakeLists.txt @@ -1,7 +1,15 @@ -find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) +set(Boost_NO_SYSTEM_PATHS ON) +set(Boost_USE_MULTITHREADED ON) +set(Boost_USE_STATIC_LIBS ON) +set(Boost_USE_STATIC_RUNTIME ON) +set(BOOST_ALL_DYN_LINK OFF) + +if (NOT Boost_ROOT AND EXISTS $ENV{BOOSTROOT}) + set(Boost_ROOT $ENV{BOOSTROOT}) +endif() -message(STATUS "Qt6 directory: $ENV{QTDIR}") -set(QT_BIN_DIR "$ENV{QTDIR}/bin") +find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets) +find_package(Boost REQUIRED) if (WIN32) add_executable(${PROJECT_NAME} WIN32 @@ -13,4 +21,4 @@ else () ) endif () -target_link_libraries(${PROJECT_NAME} PRIVATE qt) +target_link_libraries(${PROJECT_NAME} PRIVATE qt boost) diff --git a/bin/main.cpp b/bin/main.cpp index bb00efe..5157364 100644 --- a/bin/main.cpp +++ b/bin/main.cpp @@ -1,5 +1,7 @@ #include +#include + #include #include #include @@ -14,6 +16,9 @@ static constexpr const char* kFormat = "hh:mm:ss"; } // namespace int main(int argc, char** argv) { + // Boost.Filesystem (requires linking) + std::cout << "CWD: " << boost::filesystem::current_path().string() << "\n"; + if (argc > 1) { std::cout << "No CLI arguments allowed.\n"; return 0; diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index bad6b2a..27991a2 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -2,4 +2,5 @@ cmake_minimum_required(VERSION 3.25) if(NOT TESTS_ONLY) add_subdirectory(qt) + add_subdirectory(boost) endif() diff --git a/lib/boost/CMakeLists.txt b/lib/boost/CMakeLists.txt new file mode 100644 index 0000000..3773678 --- /dev/null +++ b/lib/boost/CMakeLists.txt @@ -0,0 +1,100 @@ +# Error if building out of a build directory +file(TO_CMAKE_PATH "${PROJECT_BINARY_DIR}/CMakeLists.txt" LOC_PATH) +if(EXISTS "${LOC_PATH}") + message(FATAL_ERROR "You cannot build in a source directory (or any directory with " + "CMakeLists.txt file). Please make a build subdirectory. Feel free to " + "remove CMakeCache.txt and CMakeFiles.") +endif() + +set(BOOST_VERSION "1.83.0") +set(BOOST_VERSION_UNDERSCORE "1_83_0") +set(BOOST_SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/boost_${BOOST_VERSION_UNDERSCORE}") +# b2 stage (default) puts libs in /stage/lib or stage/lib//, headers stay in +set(BOOST_STAGE_DIR "${BOOST_SOURCE_DIR}/stage") +set(BOOST_STAGE_LIB_DIR "${BOOST_SOURCE_DIR}/stage/lib") +set(ENV{BOOSTROOT} ${BOOST_SOURCE_DIR}) + +# If we already built Boost here (stage), use it directly and skip find_package/build +if(EXISTS "${BOOST_SOURCE_DIR}/boost/version.hpp") + if(EXISTS "${BOOST_STAGE_DIR}") + set(Boost_ROOT ${BOOST_SOURCE_DIR}) + endif() +endif() + +find_package(Boost 1.83 QUIET) + +if(NOT Boost_FOUND) + message(STATUS "Boost not found. Downloading and building Boost...") + + set(BOOST_ARCHIVE_URL "https://archives.boost.io/release/${BOOST_VERSION}/source/boost_${BOOST_VERSION_UNDERSCORE}.tar.gz") + set(BOOST_ARCHIVE_FILE "${CMAKE_CURRENT_BINARY_DIR}/boost_${BOOST_VERSION_UNDERSCORE}.tar.gz") + + message(STATUS "Downloading Boost from archives.boost.io...") + file(DOWNLOAD ${BOOST_ARCHIVE_URL} ${BOOST_ARCHIVE_FILE} + SHOW_PROGRESS) + + message(STATUS "Unpacking the archive...") + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ${BOOST_ARCHIVE_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + OUTPUT_QUIET + ) + + message(STATUS "Running bootstrap...") + if(WIN32) + execute_process(COMMAND "${BOOST_SOURCE_DIR}/bootstrap.bat" gcc + WORKING_DIRECTORY ${BOOST_SOURCE_DIR}) + set(B2_EXECUTABLE "${BOOST_SOURCE_DIR}/b2.exe") + else() + execute_process(COMMAND "${BOOST_SOURCE_DIR}/bootstrap.sh" --with-toolset=gcc + WORKING_DIRECTORY ${BOOST_SOURCE_DIR}) + set(B2_EXECUTABLE "${BOOST_SOURCE_DIR}/b2") + endif() + + message(STATUS "Building Boost with b2 stage (this may take a long time)...") + execute_process( + COMMAND ${B2_EXECUTABLE} stage + toolset=gcc + address-model=64 + link=static + runtime-link=static + threading=multi + --layout=versioned + --build-type=complete + WORKING_DIRECTORY ${BOOST_SOURCE_DIR} + ) + + set(Boost_ROOT "${BOOST_SOURCE_DIR}") + find_package(Boost 1.83 QUIET) +else() + message(STATUS "Boost found in the system.") +endif() + +# When using our staged Boost, FindBoost does not set Boost_LIBRARIES; collect built libs from stage. +# b2 --build-type=complete produces both release (-mt-s-) and debug (-mt-sd-) variants; link only one +# to avoid multiple definition errors. +if(Boost_FOUND AND EXISTS "${BOOST_STAGE_LIB_DIR}") + file(GLOB_RECURSE _stage_libs "${BOOST_STAGE_LIB_DIR}/*.a" "${BOOST_STAGE_LIB_DIR}/*.lib") + if(_stage_libs) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + list(FILTER _stage_libs INCLUDE REGEX "[-]mt[-]sd[-]|[-]sgd[-]") + else() + list(FILTER _stage_libs EXCLUDE REGEX "[-]mt[-]sd[-]|[-]sgd[-]") + endif() + set(Boost_LIBRARIES ${_stage_libs}) + endif() +elseif(Boost_FOUND) + set(Boost_LIBRARIES boost_filesystem boost_system boost_chrono boost_date_time boost_regex boost_program_options boost_serialization boost_thread boost_wave boost_iostreams boost_locale boost_unit_test_framework boost_wave boost_iostreams boost_locale boost_unit_test_framework) + if(LINUX) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") + endif() +endif() +# Do not pass NOTFOUND to the linker +if(Boost_LIBRARIES) + list(FILTER Boost_LIBRARIES EXCLUDE REGEX "NOTFOUND$") +endif() + +add_library(boost INTERFACE) +target_include_directories(boost INTERFACE ${Boost_INCLUDE_DIRS}) +if(Boost_LIBRARIES) + target_link_libraries(boost INTERFACE ${Boost_LIBRARIES}) +endif()