Gernot Walzl

C++

This is a template for C++ projects.

Contents

Directory Structure

Markdown

Markdown is a lightweight markup language for text formatting.

Each project should include a readme file with the following information:

README.md
# HelloWorld

This application prints *Hello World!* on screen.
The intention is to have a template for C++ projects.

## How to build

### CMake

```
mkdir -p build/Release
cd build/Release
cmake ../..
cmake --build . --config Release
```

### Conan

```
mkdir build
cd build
conan install --build=missing ..
conan build ..
```

## Running the tests

```
cd build/Release
ctest
```

## Usage

```
cd build/Release
./bin/hello [name]
```

CMake

CMake is the de facto standard build system for C++.

CMakeLists.txt
cmake_minimum_required(VERSION 3.15)

project(HelloWorld CXX)

include(CTest)

find_package(Boost REQUIRED)

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

include_directories(src)
add_subdirectory(src)

if(BUILD_TESTING)
    enable_testing()
    add_subdirectory(test)
endif()
src/CMakeLists.txt
add_subdirectory(util)

set(hello_SOURCES
    main.cpp)
add_executable(hello ${hello_SOURCES})
target_link_libraries(hello util)

install(TARGETS hello
        RUNTIME DESTINATION bin)
src/util/CMakeLists.txt
set(util_HEADERS
    simple_replacer.hpp)
set(util_SOURCES
    simple_replacer.cpp)
add_library(util ${util_SOURCES} ${util_HEADERS})
set_target_properties(util PROPERTIES PUBLIC_HEADER "${util_HEADERS}")
target_include_directories(util PRIVATE ${Boost_INCLUDE_DIRS})
target_link_libraries(util ${Boost_LIBRARIES})

install(TARGETS util
        ARCHIVE DESTINATION lib
        LIBRARY DESTINATION lib
        PUBLIC_HEADER DESTINATION include/util)
test/CMakeLists.txt
add_subdirectory(util)
test/util/CMakeLists.txt
add_executable(simple_replacer_test simple_replacer_test.cpp)
target_link_libraries(simple_replacer_test util)
add_test(NAME simple_replacer COMMAND simple_replacer_test)

Conan

Conan is a package manager for C++.

conanfile.py
from conan import ConanFile
from conan.errors import ConanException
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps
from conan.tools.scm import Git
from conan.tools.files import update_conandata


class HelloWorldRecipe(ConanFile):
    name = "helloworld"
    package_type = "application"
    settings = "os", "compiler", "build_type", "arch"

    def export(self):
        git = Git(self, self.recipe_folder)
        scm_url, scm_commit = git.get_url_and_commit()
        self.output.info(f"Obtained URL: {scm_url} and {scm_commit}")
        update_conandata(self, {
            "sources": {"commit": scm_commit, "url": scm_url}
        })

    def source(self):
        git = Git(self)
        sources = self.conan_data["sources"]
        self.output.info(f"Cloning sources from: {sources}")
        git.clone(url=sources["url"], target=".")
        git.checkout(commit=sources["commit"])

    def set_version(self):
        try:
            git = Git(self, self.recipe_folder)
            self.version = git.run("describe --tags")
            if self.version[0] == "v":
                self.version = self.version[1:]
        except ConanException as exc:
            self.output.warning(f"Exception in set_version: {exc}")
            self.version = "undef"

    def requirements(self):
        self.requires("boost/1.81.0")

    def layout(self):
        cmake_layout(self)

    def generate(self):
        deps = CMakeDeps(self)
        deps.generate()
        tc = CMakeToolchain(self)
        tc.generate()

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def package(self):
        cmake = CMake(self)
        cmake.install()

Git

Git is a version control system that tracks changes in code.

The build directory is excluded from tracking changes.

.gitignore
build

Clang-Format

Clang-Format is a tool to format code.

.clang-format
BasedOnStyle: WebKit
NamespaceIndentation: None

Header Files

src/util/simple_replacer.hpp
#pragma once

#include <string>

namespace util {

class SimpleReplacer {
public:
    explicit SimpleReplacer(const std::string& content);
    virtual ~SimpleReplacer();

    void replaceAll(const std::string& search, const std::string& replace);
    std::string getContent() const;

private:
    std::string content_;
};

} // namespace util

Source Files

src/main.cpp
#include "util/simple_replacer.hpp"
#include <iostream>
#include <string>

int main(int argc, char* argv[])
{
    std::string msg("Hello World!");
    if (argc >= 2) {
        util::SimpleReplacer replacer(msg);
        replacer.replaceAll("World", argv[1]);
        msg = replacer.getContent();
    }
    std::cout << msg << std::endl;
}
src/util/simple_replacer.cpp
#include "simple_replacer.hpp"
#include <boost/algorithm/string.hpp>

namespace util {

SimpleReplacer::SimpleReplacer(const std::string& content)
    : content_(content)
{
}

SimpleReplacer::~SimpleReplacer() = default;

void SimpleReplacer::replaceAll(const std::string& search,
    const std::string& replace)
{
    boost::replace_all(content_, search, replace);
}

std::string SimpleReplacer::getContent() const
{
    return content_;
}

} // namespace util
test/util/simple_replacer_test.cpp
#include "util/simple_replacer.hpp"

int main()
{
    std::string content("Just a test.");
    util::SimpleReplacer replacer(content);
    replacer.replaceAll("a", "another");
    std::string result = replacer.getContent();
    std::string expected("Just another test.");
    if (result == expected) {
        return 0;
    }
    return 1;
}
CONTENT.html source 2023-11-18 11.4 KB
HelloWorld-0.1.0.tar.gz sha256 2023-11-18 2.4 KB