DEV Community

Fahad Ali Khan
Fahad Ali Khan

Posted on

Streamlining C++ Project Releases with CMake and Vcpkg

Releasing software can often feel like navigating a labyrinth of tools, configurations, and best practices. As a C++ developer, ensuring that your project is easily accessible and installable for users across different platforms is paramount. In this blog post, I'll walk you through the process I undertook to release my C++ project, EnglishFormatter, using CMake and Vcpkg. I'll share the tools I chose, the step-by-step release process, the lessons learned, the adjustments made to my project, insights from user testing, and comprehensive instructions for users to install and utilize the tool.

Table of Contents


Choosing the Right Tools

Selecting the appropriate tools is crucial for a smooth release process. For EnglishFormatter, I opted for:

  • CMake: A versatile build system generator that simplifies the build process across different platforms.
  • Vcpkg: A C++ library manager that handles dependencies efficiently, ensuring reproducible builds.
  • GitHub Releases: Leveraging GitHub's built-in release management to distribute binaries and source code.

Links:


Process for Creating a Release

1. Setting Up the Project with CMake

CMake was chosen as the build system due to its cross-platform capabilities and seamless integration with various package managers. Here's how I configured CMake for EnglishFormatter:

  • CMakeLists.txt: Defined the project, set the C++ standard to C++20, and specified the toolchain file for Vcpkg.
  cmake_minimum_required(VERSION 3.20)

  # Enable Vcpkg manifest mode before the project command
  set(VCPKG_MANIFEST_MODE ON CACHE BOOL "Enable Vcpkg manifest mode")

  project(EnglishFormatter VERSION 1.0.0 LANGUAGES CXX)

  # Set C++ standard to C++20
  set(CMAKE_CXX_STANDARD 20)
  set(CMAKE_CXX_STANDARD_REQUIRED ON)

  # ------------------------
  # Core Library Configuration
  # ------------------------

  # Collect all source files for the core library, excluding cli.cpp
  file(GLOB CORE_SOURCES CONFIGURE_DEPENDS cli_app/src/*.cpp)

  # Exclude cli.cpp from CORE_SOURCES to prevent multiple main definitions
  list(FILTER CORE_SOURCES EXCLUDE REGEX ".*/cli\\.cpp$")

  # Define the core library
  add_library(core_lib STATIC ${CORE_SOURCES})

  # Include directories for the core library
  target_include_directories(core_lib PUBLIC cli_app/include)

  # Find and link CURL and fmt libraries
  find_package(CURL REQUIRED)
  find_package(fmt REQUIRED)
  target_link_libraries(core_lib PUBLIC CURL::libcurl fmt::fmt)

  # ------------------------
  # GoogleTest and GoogleMock Configuration
  # ------------------------
  include(FetchContent)

  # Fetch GoogleTest (which includes GoogleMock)
  FetchContent_Declare(
    googletest
    URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip
    DOWNLOAD_EXTRACT_TIMESTAMP ON
  )

  # Prevent overriding the parent project's compiler/linker settings
  if(MSVC)
    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
  endif()

  # Enable building GMock and GTest
  set(BUILD_GMOCK ON CACHE BOOL "" FORCE)
  set(BUILD_GTEST ON CACHE BOOL "" FORCE)

  FetchContent_MakeAvailable(googletest)

  # Enable testing before defining tests
  enable_testing()

  # ------------------------
  # Main Executable Configuration
  # ------------------------

  # Define the main executable and link it against the core library
  add_executable(EnglishFormatter cli_app/src/cli.cpp)
  target_link_libraries(EnglishFormatter PRIVATE core_lib)

  # ------------------------
  # Test Executable Configuration
  # ------------------------

  # Collect all test source files
  file(GLOB TEST_SOURCES CONFIGURE_DEPENDS cli_app/tests/*.cpp)

  # Define the test executable
  add_executable(EnglishFormatterTests ${TEST_SOURCES})

  # Include directories for tests
  target_include_directories(EnglishFormatterTests PRIVATE cli_app/include)

  # Link test executable against GMock, GTest, GTest main, and the core library
  target_link_libraries(EnglishFormatterTests 
      PRIVATE 
          gmock 
          gtest 
          gtest_main
          core_lib
  )

  # Register the tests
  add_test(NAME EnglishFormatterTests COMMAND EnglishFormatterTests)
Enter fullscreen mode Exit fullscreen mode

2. Managing Dependencies with Vcpkg

Vcpkg was instrumental in managing the project's dependencies, ensuring that all required libraries were correctly installed and linked. Here's how I integrated Vcpkg:

  • Installing Vcpkg:
  git clone https://github.com/microsoft/vcpkg.git
  cd vcpkg
  ./bootstrap-vcpkg.sh
Enter fullscreen mode Exit fullscreen mode
  • Installing Dependencies:
  ./vcpkg install curl fmt
Enter fullscreen mode Exit fullscreen mode
  • Using Vcpkg with CMake:

When configuring the project with CMake, I specified the toolchain file provided by Vcpkg:

  cmake .. -DCMAKE_TOOLCHAIN_FILE=path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
Enter fullscreen mode Exit fullscreen mode

Note: Replace path/to/vcpkg with the actual path to your Vcpkg installation.

3. Configuring Git for Releases

Git tags are pivotal in marking specific points in the project's history, such as releases. Here's how I managed Git tags:

  • Committing Changes:
  git add .
  git commit -m "Prepare for release 1.0.0"
Enter fullscreen mode Exit fullscreen mode
  • Creating an Annotated Tag:
  git tag -a v1.0.0 -m "Release version 1.0.0"
Enter fullscreen mode Exit fullscreen mode
  • Pushing Tags to GitHub:
  git push origin main
  git push --follow-tags
Enter fullscreen mode Exit fullscreen mode

This approach ensures that the release is clearly marked in the project's history and is easily accessible for future reference.

4. Building and Testing

With the project configured, the next step was to build and test it to ensure everything functioned as expected.

  • Building the Project:
  mkdir build
  cd build
  cmake .. -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake
  cmake --build . --config Release
Enter fullscreen mode Exit fullscreen mode
  • Running Tests:
  ctest --output-on-failure
Enter fullscreen mode Exit fullscreen mode

This process verified that the core library and executables were correctly built and that the tests passed, ensuring the reliability of the release.

5. Publishing the Release on GitHub

Publishing the release on GitHub made it accessible to users and integrated with the project's version control.

  • Creating a Release on GitHub:
  1. Navigate to the GitHub repository.
  2. Click on the "Releases" tab.
  3. Click "Draft a new release".
  4. Select the tag v1.0.0.
  5. Provide a release title and description.
  6. Attach any build artifacts if necessary (e.g., binaries for different platforms).
  7. Click "Publish release".

This step officially marks the version 1.0.0 of EnglishFormatter as available for users to download and install.


Lessons Learned

Embarking on this release journey was both enlightening and challenging. Here are some key takeaways:

  1. Importance of Proper Configuration Order: Setting variables like CMAKE_TOOLCHAIN_FILE and VCPKG_MANIFEST_MODE before the project() command in CMakeLists.txt was crucial. Misplacing these led to initial configuration issues.

  2. Managing Dependencies: Vcpkg simplified dependency management, but ensuring all dependencies were correctly listed in vcpkg.json prevented potential build issues.

  3. Git Tagging Best Practices: Using annotated tags with clear messages aids in maintaining a clean project history and facilitates easier rollbacks if needed.

  4. Documentation is Key: Clear and comprehensive documentation in README.md ensures users can install and use the tool without hiccups.

  5. User Testing Insights: Real-world testing highlighted areas where documentation could be improved, emphasizing the need for user-centric documentation.


Adjustments Made to the Project

To accommodate the release process using CMake and Vcpkg, several modifications were necessary:

  • Integration of Vcpkg: Added vcpkg.json to manage dependencies and adjusted CMakeLists.txt to enable Vcpkg manifest mode.

  • Build Configuration: Configured output directories in CMake to organize binaries systematically.

  • Testing Setup: Incorporated GoogleTest and GoogleMock for unit testing, ensuring the core functionalities were reliable.

  • Documentation Enhancements: Expanded README.md with detailed installation, configuration, and usage instructions to guide users effectively.

These changes streamlined the build process, ensured dependency consistency, and enhanced the overall usability of EnglishFormatter.


User Testing with macOS

To validate the installation and usage instructions, I enlisted the help of a friend who uses macOS. Here's how the session unfolded:

Setup

  1. Preparation: Shared the updated README.md with my friend, highlighting the installation steps.
  2. Environment: My friend ensured they had CMake, Vcpkg, and a C++20-compatible compiler installed on their macOS system.

Testing Process

  1. Cloning the Repository:
   git clone https://github.com/yourusername/EnglishFormatter.git
   cd EnglishFormatter
Enter fullscreen mode Exit fullscreen mode
  1. Setting Up Vcpkg:
   git clone https://github.com/microsoft/vcpkg.git
   cd vcpkg
   ./bootstrap-vcpkg.sh
   ./vcpkg install curl fmt
   cd ..
Enter fullscreen mode Exit fullscreen mode
  1. Configuring and Building the Project:
   mkdir build
   cd build
   cmake .. -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake
   cmake --build . --config Release
Enter fullscreen mode Exit fullscreen mode
  1. Running the Application:
   ./EnglishFormatter
Enter fullscreen mode Exit fullscreen mode

Observations and Feedback

  • Smooth Installation: The installation steps were clear, and my friend was able to set up the environment without issues.
  • Execution Clarity: Running the executable and navigating the interactive menu was straightforward.
  • Minor Confusion: Initially, my friend was unsure about specifying the path to the Vcpkg toolchain file. Clarifying this step helped resolve the confusion.
  • Documentation Improvements: Based on the feedback, I added more explicit instructions regarding the toolchain file path and included troubleshooting tips for common issues.

Corrections Made

  • Toolchain File Path: Provided a clearer explanation of how to locate and specify the Vcpkg toolchain file during the CMake configuration.
  • Environment Setup: Included additional details on ensuring that Vcpkg is correctly set up before building the project.

This user testing session was invaluable in refining the documentation, ensuring that users across different platforms can effortlessly install and utilize EnglishFormatter.


Installing and Using EnglishFormatter

With the release now live, users can easily install and use EnglishFormatter on their systems. Here's a comprehensive guide to get you started.

Installation Steps

  1. Install Vcpkg

Vcpkg is essential for managing dependencies. Follow these steps to install it:

   git clone https://github.com/microsoft/vcpkg.git
   cd vcpkg
   ./bootstrap-vcpkg.sh
Enter fullscreen mode Exit fullscreen mode

For detailed instructions, refer to the Vcpkg Quick Start Guide.

  1. Clone the EnglishFormatter Repository
   git clone https://github.com/yourusername/EnglishFormatter.git
   cd EnglishFormatter
Enter fullscreen mode Exit fullscreen mode
  1. Set Up the .env File

Create a .env file in the project's root directory to store your API key:

   API_KEY=your_api_key_here
Enter fullscreen mode Exit fullscreen mode

Replace your_api_key_here with your actual API key from your language model provider (e.g., OpenAI).

  1. Build the Project
   mkdir build
   cd build
   cmake .. -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake
   cmake --build . --config Release
Enter fullscreen mode Exit fullscreen mode

Note: Ensure that the path to vcpkg in the CMAKE_TOOLCHAIN_FILE flag is correct based on your system setup.

Usage Instructions

Once built, you can use EnglishFormatter to format, summarize, or paraphrase your text documents.

Running via Command-Line Options

./EnglishFormatter [options]
Enter fullscreen mode Exit fullscreen mode

Available Options:

  • -h, --help : Show help message and exit.
  • -v, --version : Show the tool's version and exit.
  • -m, --model MODEL : Specify the language model to use (default: gpt-3.5-turbo).
  • -o, --output SUFFIX : Specify the output file suffix (default: _modified).
  • -t, --token-usage : Show token usage and exit.

Example:

Formatting documents with a specific model and output suffix:

./EnglishFormatter --model gpt-4 --output _formatted
Enter fullscreen mode Exit fullscreen mode

Using the Interactive Menu

Simply run the executable without any arguments to access the interactive menu:

./EnglishFormatter
Enter fullscreen mode Exit fullscreen mode

Menu Options:

  • Format document: Improve the readability and structure of your text files.
  • Summarize document: Generate concise summaries of your documents.
  • Paraphrase document: Rephrase your text while retaining the original meaning.
  • Exit: Close the application.

Navigation:

  • Use the Up and Down arrow keys to navigate through the menu.
  • Press Enter to select an option.

Processing Files:

  1. Select the desired action from the menu.
  2. When prompted, enter the names of the files you wish to process, separated by spaces.
  3. The tool will process each file and save the output with the specified suffix.

Conclusion

Releasing EnglishFormatter was a rewarding experience that underscored the importance of structured build systems, efficient dependency management, and comprehensive documentation. By leveraging CMake and Vcpkg, I ensured that the project is easily buildable across different platforms, making it accessible to a broader user base. The user testing session highlighted the significance of clear instructions, prompting necessary refinements to the documentation. As a result, users can now seamlessly install and utilize EnglishFormatter, enhancing their text processing tasks with advanced language models.


Resources and Links

- Github Repo

Feel free to reach out via the GitHub Issues page or contact me directly for any questions, suggestions, or support regarding EnglishFormatter.

Happy Formatting!

Top comments (0)