cpp

exercises

exercises.cpp⚙️
/**
 * CMake Exercises
 * 
 * These exercises guide you through creating CMake projects.
 * Each exercise builds on the previous one.
 */

#include <iostream>
#include <string>

// ============================================================================
// EXERCISE 1: Minimal CMake Project
// ============================================================================
/*
 * Create a minimal CMake project that compiles a "Hello, World!" program.
 * 
 * Requirements:
 * 1. Create a directory structure:
 *    exercise1/
 *    ├── CMakeLists.txt
 *    └── main.cpp
 * 
 * 2. CMakeLists.txt should:
 *    - Set minimum CMake version to 3.16
 *    - Define project named "HelloWorld"
 *    - Create executable "hello" from main.cpp
 *    - Set C++17 standard
 * 
 * 3. Build and run:
 *    mkdir build && cd build
 *    cmake ..
 *    cmake --build .
 *    ./hello
 * 
 * Write your CMakeLists.txt:
 */

// main.cpp for Exercise 1
void exercise1_main() {
    std::cout << "Hello, CMake World!" << std::endl;
}

/*
 * Expected CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(HelloWorld LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(hello main.cpp)

*/

// ============================================================================
// EXERCISE 2: Multiple Source Files
// ============================================================================
/*
 * Create a project with multiple source files.
 * 
 * Directory structure:
 *    exercise2/
 *    ├── CMakeLists.txt
 *    ├── main.cpp
 *    ├── math_utils.hpp
 *    └── math_utils.cpp
 * 
 * Requirements:
 * 1. Create math_utils with functions: add, subtract, multiply, divide
 * 2. main.cpp uses these functions
 * 3. CMakeLists.txt includes both source files
 * 
 * Write your CMakeLists.txt to compile both files together.
 */

// math_utils.hpp
namespace math {
    double add(double a, double b);
    double subtract(double a, double b);
    double multiply(double a, double b);
    double divide(double a, double b);
}

// math_utils.cpp
/*
#include "math_utils.hpp"
#include <stdexcept>

namespace math {
    double add(double a, double b) { return a + b; }
    double subtract(double a, double b) { return a - b; }
    double multiply(double a, double b) { return a * b; }
    double divide(double a, double b) {
        if (b == 0) throw std::runtime_error("Division by zero");
        return a / b;
    }
}
*/

// main.cpp
/*
#include <iostream>
#include "math_utils.hpp"

int main() {
    std::cout << "10 + 5 = " << math::add(10, 5) << std::endl;
    std::cout << "10 - 5 = " << math::subtract(10, 5) << std::endl;
    std::cout << "10 * 5 = " << math::multiply(10, 5) << std::endl;
    std::cout << "10 / 5 = " << math::divide(10, 5) << std::endl;
    return 0;
}
*/

// ============================================================================
// EXERCISE 3: Create a Library
// ============================================================================
/*
 * Create a static library and link it to an executable.
 * 
 * Directory structure:
 *    exercise3/
 *    ├── CMakeLists.txt
 *    ├── include/
 *    │   └── stringutils.hpp
 *    ├── src/
 *    │   └── stringutils.cpp
 *    └── app/
 *        └── main.cpp
 * 
 * Requirements:
 * 1. Create a library "stringutils" with functions:
 *    - to_upper(string) -> string
 *    - to_lower(string) -> string
 *    - trim(string) -> string
 * 2. Set include directories properly
 * 3. Link library to executable
 * 
 * Write your CMakeLists.txt:
 */

/*
 * Expected CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(StringUtils LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Create library
add_library(stringutils src/stringutils.cpp)

target_include_directories(stringutils
    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Create executable
add_executable(string_app app/main.cpp)

# Link library to executable
target_link_libraries(string_app PRIVATE stringutils)

*/

// ============================================================================
// EXERCISE 4: Compiler Warnings and Options
// ============================================================================
/*
 * Add comprehensive compiler warnings to your project.
 * 
 * Requirements:
 * 1. Add warnings for GCC/Clang: -Wall -Wextra -Wpedantic -Werror
 * 2. Add warnings for MSVC: /W4 /WX
 * 3. Use generator expressions for cross-platform support
 * 4. Add DEBUG_MODE definition in Debug builds
 * 
 * Add these lines to your CMakeLists.txt:
 */

/*
 * Expected additions:

# Compiler warnings (add to any target)
target_compile_options(myapp PRIVATE
    $<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wpedantic -Werror>
    $<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wpedantic -Werror>
    $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
)

# Debug definitions
target_compile_definitions(myapp PRIVATE
    $<$<CONFIG:Debug>:DEBUG_MODE>
    $<$<CONFIG:Release>:NDEBUG>
)

*/

// ============================================================================
// EXERCISE 5: Subdirectories
// ============================================================================
/*
 * Create a project with multiple subdirectories.
 * 
 * Directory structure:
 *    exercise5/
 *    ├── CMakeLists.txt          (root)
 *    ├── libs/
 *    │   ├── CMakeLists.txt
 *    │   ├── math/
 *    │   │   ├── CMakeLists.txt
 *    │   │   ├── math.hpp
 *    │   │   └── math.cpp
 *    │   └── io/
 *    │       ├── CMakeLists.txt
 *    │       ├── io.hpp
 *    │       └── io.cpp
 *    └── app/
 *        ├── CMakeLists.txt
 *        └── main.cpp
 * 
 * Requirements:
 * 1. Root CMakeLists.txt adds subdirectories
 * 2. Each library has its own CMakeLists.txt
 * 3. App links to both libraries
 * 
 * Write CMakeLists.txt for each directory:
 */

/*
 * Root CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(MultiLib LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_subdirectory(libs)
add_subdirectory(app)

*/

/*
 * libs/CMakeLists.txt:

add_subdirectory(math)
add_subdirectory(io)

*/

/*
 * libs/math/CMakeLists.txt:

add_library(mathlib math.cpp)
target_include_directories(mathlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

*/

/*
 * libs/io/CMakeLists.txt:

add_library(iolib io.cpp)
target_include_directories(iolib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

*/

/*
 * app/CMakeLists.txt:

add_executable(myapp main.cpp)
target_link_libraries(myapp PRIVATE mathlib iolib)

*/

// ============================================================================
// EXERCISE 6: Find Package
// ============================================================================
/*
 * Create a project that uses an external package (Threads).
 * 
 * Requirements:
 * 1. Find the Threads package
 * 2. Create a multi-threaded application
 * 3. Link against Threads::Threads
 * 
 * Write your CMakeLists.txt:
 */

// main.cpp for threading example
#include <thread>
#include <vector>
#include <mutex>

void exercise6_demo() {
    std::mutex mtx;
    std::vector<std::thread> threads;
    
    for (int i = 0; i < 4; ++i) {
        threads.emplace_back([&mtx, i]() {
            std::lock_guard<std::mutex> lock(mtx);
            std::cout << "Thread " << i << " running" << std::endl;
        });
    }
    
    for (auto& t : threads) {
        t.join();
    }
}

/*
 * Expected CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(ThreadedApp LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Threads REQUIRED)

add_executable(threaded_app main.cpp)
target_link_libraries(threaded_app PRIVATE Threads::Threads)

*/

// ============================================================================
// EXERCISE 7: FetchContent
// ============================================================================
/*
 * Use FetchContent to download and use nlohmann/json library.
 * 
 * Requirements:
 * 1. Fetch nlohmann/json from GitHub
 * 2. Create an app that uses the library
 * 3. Parse and create JSON
 * 
 * Write your CMakeLists.txt:
 */

/*
 * Expected CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(JsonApp LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)

FetchContent_Declare(
    json
    GIT_REPOSITORY https://github.com/nlohmann/json.git
    GIT_TAG v3.11.2
)

FetchContent_MakeAvailable(json)

add_executable(json_app main.cpp)
target_link_libraries(json_app PRIVATE nlohmann_json::nlohmann_json)

*/

// Example usage:
/*
#include <nlohmann/json.hpp>
#include <iostream>

int main() {
    nlohmann::json j;
    j["name"] = "John";
    j["age"] = 30;
    j["scores"] = {95, 87, 92};
    
    std::cout << j.dump(2) << std::endl;
    return 0;
}
*/

// ============================================================================
// EXERCISE 8: Options and Conditionals
// ============================================================================
/*
 * Create a project with configurable options.
 * 
 * Requirements:
 * 1. Option to enable/disable tests: BUILD_TESTS
 * 2. Option to enable/disable examples: BUILD_EXAMPLES
 * 3. Cache variable for log level: LOG_LEVEL (0-3)
 * 4. Conditionally add subdirectories based on options
 * 
 * Write your CMakeLists.txt:
 */

/*
 * Expected CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(ConfigurableProject LANGUAGES CXX)

# Options
option(BUILD_TESTS "Build unit tests" ON)
option(BUILD_EXAMPLES "Build example programs" ON)
set(LOG_LEVEL "1" CACHE STRING "Logging level (0=none, 3=verbose)")

# Main library
add_library(mylib src/lib.cpp)

# Conditionally add tests
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

# Conditionally add examples
if(BUILD_EXAMPLES)
    add_subdirectory(examples)
endif()

# Use the log level
target_compile_definitions(mylib PRIVATE LOG_LEVEL=${LOG_LEVEL})

*/

// ============================================================================
// EXERCISE 9: Installation
// ============================================================================
/*
 * Add installation rules to your project.
 * 
 * Requirements:
 * 1. Install the library to lib/
 * 2. Install headers to include/
 * 3. Install executable to bin/
 * 4. Generate and install CMake config files
 * 
 * Add installation rules to your CMakeLists.txt:
 */

/*
 * Expected additions:

include(GNUInstallDirs)

# Install targets
install(TARGETS mylib myapp
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

# Install headers
install(DIRECTORY include/ 
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

# Install to custom prefix:
# cmake --install build --prefix /my/install/path

*/

// ============================================================================
// EXERCISE 10: Complete Project
// ============================================================================
/*
 * Create a complete, well-structured CMake project.
 * 
 * Requirements:
 * 1. A library with public headers
 * 2. An executable using the library
 * 3. Unit tests (optional, with option)
 * 4. Compiler warnings enabled
 * 5. C++17 standard
 * 6. Installation rules
 * 7. Version information
 * 
 * Directory structure:
 *    myproject/
 *    ├── CMakeLists.txt
 *    ├── cmake/
 *    │   └── myprojectConfig.cmake.in
 *    ├── include/
 *    │   └── myproject/
 *    │       └── api.hpp
 *    ├── src/
 *    │   ├── api.cpp
 *    │   └── main.cpp
 *    └── tests/
 *        ├── CMakeLists.txt
 *        └── test_api.cpp
 * 
 * Write a complete CMakeLists.txt:
 */

/*
 * Full CMakeLists.txt:

cmake_minimum_required(VERSION 3.16)
project(MyProject
    VERSION 1.0.0
    DESCRIPTION "A complete CMake project example"
    LANGUAGES CXX
)

# Global settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Options
option(BUILD_TESTS "Build unit tests" ON)
option(BUILD_SHARED_LIBS "Build shared libraries" OFF)

# Create library
add_library(myproject_lib src/api.cpp)
add_library(MyProject::lib ALIAS myproject_lib)

target_include_directories(myproject_lib
    PUBLIC
        $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
        $<INSTALL_INTERFACE:include>
    PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/src
)

target_compile_options(myproject_lib PRIVATE
    $<$<CXX_COMPILER_ID:GNU>:-Wall -Wextra -Wpedantic>
    $<$<CXX_COMPILER_ID:Clang>:-Wall -Wextra -Wpedantic>
    $<$<CXX_COMPILER_ID:MSVC>:/W4>
)

# Create executable
add_executable(myproject src/main.cpp)
target_link_libraries(myproject PRIVATE myproject_lib)

# Tests
if(BUILD_TESTS)
    enable_testing()
    add_subdirectory(tests)
endif()

# Installation
include(GNUInstallDirs)

install(TARGETS myproject_lib myproject
    EXPORT MyProjectTargets
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
    INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

install(DIRECTORY include/
    DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

install(EXPORT MyProjectTargets
    FILE MyProjectTargets.cmake
    NAMESPACE MyProject::
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyProject
)

# Package config
include(CMakePackageConfigHelpers)

configure_package_config_file(
    ${CMAKE_CURRENT_SOURCE_DIR}/cmake/MyProjectConfig.cmake.in
    ${CMAKE_CURRENT_BINARY_DIR}/MyProjectConfig.cmake
    INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyProject
)

write_basic_package_version_file(
    ${CMAKE_CURRENT_BINARY_DIR}/MyProjectConfigVersion.cmake
    VERSION ${PROJECT_VERSION}
    COMPATIBILITY AnyNewerVersion
)

install(FILES
    ${CMAKE_CURRENT_BINARY_DIR}/MyProjectConfig.cmake
    ${CMAKE_CURRENT_BINARY_DIR}/MyProjectConfigVersion.cmake
    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyProject
)

*/

// ============================================================================
// MAIN
// ============================================================================

int main() {
    std::cout << "╔══════════════════════════════════════════════════════════════╗" << std::endl;
    std::cout << "║                    CMAKE EXERCISES                            ║" << std::endl;
    std::cout << "╚══════════════════════════════════════════════════════════════╝" << std::endl;
    
    std::cout << "\nThese exercises guide you through creating CMake projects." << std::endl;
    std::cout << "Each exercise builds on the previous one." << std::endl;
    std::cout << "\nExercises:" << std::endl;
    std::cout << "  1. Minimal CMake Project" << std::endl;
    std::cout << "  2. Multiple Source Files" << std::endl;
    std::cout << "  3. Create a Library" << std::endl;
    std::cout << "  4. Compiler Warnings" << std::endl;
    std::cout << "  5. Subdirectories" << std::endl;
    std::cout << "  6. Find Package (Threads)" << std::endl;
    std::cout << "  7. FetchContent" << std::endl;
    std::cout << "  8. Options and Conditionals" << std::endl;
    std::cout << "  9. Installation" << std::endl;
    std::cout << "  10. Complete Project" << std::endl;
    
    std::cout << "\n═══════════════════════════════════════════════════════════════" << std::endl;
    std::cout << "Create each exercise in its own directory and test!" << std::endl;
    std::cout << "Build commands:" << std::endl;
    std::cout << "  mkdir build && cd build" << std::endl;
    std::cout << "  cmake .." << std::endl;
    std::cout << "  cmake --build ." << std::endl;
    
    return 0;
}
Exercises - C++ Tutorial | DeepML