This is a template for C++ projects.
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 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 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 is a version control system that tracks changes in code.
The build directory is excluded from tracking changes.
.gitignore
build
Clang-Format is a tool to format code.
.clang-format
BasedOnStyle: WebKit
NamespaceIndentation: None
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
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;
}