From edf2fe14a1312e4d7db98718a126f7c479798b77 Mon Sep 17 00:00:00 2001 From: MialLewis <95620982+MialLewis@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:23:50 +0000 Subject: [PATCH 1/7] add boost binding --- CMakeLists.txt | 2 +- api/CMakeLists.txt | 12 +++++++++++- environment.yml | 4 +++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ec10d44..0f94175 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,4 +21,4 @@ add_subdirectory(api) add_executable(basicSetup main.cpp) # Add libraries -target_link_libraries(basicSetup PUBLIC kernel api) \ No newline at end of file +target_link_libraries(basicSetup PUBLIC kernel api) diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index 9696db4..8bf0f74 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -11,4 +11,14 @@ target_link_libraries(api PRIVATE kernel) # Setup python interface and link API lib pybind11_add_module(basicSetupApi ${CMAKE_CURRENT_SOURCE_DIR}/pythonInterface/apiBindings.cpp) -target_link_libraries(basicSetupApi PRIVATE api) \ No newline at end of file +target_link_libraries(basicSetupApi PRIVATE api) + +### Boost Python API +find_package(Boost REQUIRED COMPONENTS python313) +find_package(Python3 REQUIRED COMPONENTS Interpreter Development) + +# Create boost api library +add_library(api_boost MODULE ${CMAKE_CURRENT_SOURCE_DIR}/pythonInterface/apiBindingsBoost.cpp) +target_include_directories(api_boost PRIVATE ${Boost_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}) +target_link_libraries(api_boost PRIVATE Boost::boost Boost::python313 ${Python3_LIBRARIES}) +set_target_properties(api_boost PROPERTIES PREFIX "" SUFFIX ".pyd") \ No newline at end of file diff --git a/environment.yml b/environment.yml index 500b254..49f5acb 100644 --- a/environment.yml +++ b/environment.yml @@ -3,4 +3,6 @@ name: basic-setup dependencies: - python - pybind11 - - cmake \ No newline at end of file + - cmake + - libboost-devel + - libboost-python-devel From 5f313904a94eaccc872c7d86f9a4ce489a48f6b4 Mon Sep 17 00:00:00 2001 From: MialLewis <95620982+MialLewis@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:51:53 +0000 Subject: [PATCH 2/7] add boost bindings api source --- api/pythonInterface/apiBindingsBoost.cpp | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 api/pythonInterface/apiBindingsBoost.cpp diff --git a/api/pythonInterface/apiBindingsBoost.cpp b/api/pythonInterface/apiBindingsBoost.cpp new file mode 100644 index 0000000..919f0a6 --- /dev/null +++ b/api/pythonInterface/apiBindingsBoost.cpp @@ -0,0 +1,29 @@ +#include + +class ComplexNumber { +private: + double m_real; + double m_imaginary; + +public: + ComplexNumber() : m_real(0), m_imaginary(0) {}; + ComplexNumber(double real, double imaginary) : m_real(real), m_imaginary(imaginary) {}; + const double getReal() const { return m_real; } + const double getImaginary() const { return m_imaginary; } + + ComplexNumber ComplexNumber::operator+(const ComplexNumber& rhs) { return ComplexNumber(m_real + rhs.getReal(), m_imaginary + rhs.getImaginary()); } +}; + + + +int add(int a, int b) { + return a + b; +} + +BOOST_PYTHON_MODULE(api_boost) { + using namespace boost::python; + def("add", add); + + class_("ComplexNumber", init()) + .def("__add__", &ComplexNumber::operator+, (arg("left"), arg("right"))); +} From 26855154375b1aa9f1e3858346ee89a101f95b36 Mon Sep 17 00:00:00 2001 From: MialLewis <95620982+MialLewis@users.noreply.github.com> Date: Wed, 29 Jan 2025 23:59:38 +0000 Subject: [PATCH 3/7] add print function to export --- api/pythonInterface/apiBindingsBoost.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/api/pythonInterface/apiBindingsBoost.cpp b/api/pythonInterface/apiBindingsBoost.cpp index 919f0a6..092b744 100644 --- a/api/pythonInterface/apiBindingsBoost.cpp +++ b/api/pythonInterface/apiBindingsBoost.cpp @@ -1,4 +1,5 @@ #include +#include class ComplexNumber { private: @@ -12,6 +13,7 @@ class ComplexNumber { const double getImaginary() const { return m_imaginary; } ComplexNumber ComplexNumber::operator+(const ComplexNumber& rhs) { return ComplexNumber(m_real + rhs.getReal(), m_imaginary + rhs.getImaginary()); } + void print() { std::cout << m_real << ", " << m_imaginary; } }; @@ -25,5 +27,6 @@ BOOST_PYTHON_MODULE(api_boost) { def("add", add); class_("ComplexNumber", init()) - .def("__add__", &ComplexNumber::operator+, (arg("left"), arg("right"))); + .def("__add__", &ComplexNumber::operator+, (arg("left"), arg("right"))) + .def("print", &ComplexNumber::print); } From 3ae4e650ead4ea01f94244587911966d2abb5e52 Mon Sep 17 00:00:00 2001 From: MialLewis <95620982+MialLewis@users.noreply.github.com> Date: Thu, 30 Jan 2025 12:26:23 +0000 Subject: [PATCH 4/7] add cppcheck and ninja generator --- CMakeLists.txt | 29 ++++++++++++++++ CMakePresets.json | 14 +++++++- README.md | 42 ++++++++++++++++++++---- api/CMakeLists.txt | 4 +-- api/pythonInterface/apiBindingsBoost.cpp | 2 +- environment.yml | 4 ++- 6 files changed, 83 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0f94175..885939b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.22) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export compile commands so cppcheck is aware of compiler options and paths # Define the project name. project(basicSetup) @@ -22,3 +23,31 @@ add_executable(basicSetup main.cpp) # Add libraries target_link_libraries(basicSetup PUBLIC kernel api) + +# Set up cppcheck + +# Set up cppcheck build directory and cache +set(CPPCHECK_BUILD_DIR "${CMAKE_BINARY_DIR}/cppcheck") +file(MAKE_DIRECTORY "${CPPCHECK_BUILD_DIR}" "${CPPCHECK_BUILD_DIR}/cache") +find_program(CPPCHECK_EXECUTABLE NAMES cppcheck) + +set(CPPCHECK_ARGS + --enable=all + --check-level=exhaustive + --inline-suppr + --max-configs=120 + --std=c++${CMAKE_CXX_STANDARD} # use the standard from cmake + --cppcheck-build-dir="${CPPCHECK_BUILD_DIR}/cache" + --project="${CMAKE_BINARY_DIR}/compile_commands.json" +) + +if(CPPCHECK_EXECUTABLE) + message(STATUS "Found cppcheck: ${CPPCHECK_EXECUTABLE}") + add_custom_target( + cppcheck + COMMAND ${CPPCHECK_EXECUTABLE} ${CPPCHECK_ARGS} + COMMENT "Running cppcheck static analysis" + ) +else() + message(WARNING "cppcheck not found. Static analysis will be skipped.") +endif() \ No newline at end of file diff --git a/CMakePresets.json b/CMakePresets.json index 198baff..44e094b 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,7 +7,7 @@ }, "configurePresets": [ { - "name": "windows-default", + "name": "win-msbuild", "displayName": "Windows x64 Debug", "description": "Sets msvc generator, compilers, x64 architecture, build and install directory, debug build type", "generator": "Visual Studio 17 2022", @@ -15,6 +15,18 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } + }, + { + "name": "win-ninja", + "displayName": "Windows x64 Debug Ninja", + "description": "Sets ninja generator, compilers, x64 architecture, build and install directory, debug build type", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_C_COMPILER": "cl", + "CMAKE_CXX_COMPILER": "cl" + } } ] } diff --git a/README.md b/README.md index 5cba17e..35a1d86 100644 --- a/README.md +++ b/README.md @@ -3,32 +3,60 @@ This is a repository that represents a basic, minimal, c++ project setup using cmake and conda. This currently includes: - Creation of a `kernel` library. - Creation of an `api` library to expose this `kernel` library. -- Creation of a python interface to enable access to the `api` from python. +- Creation of a python interface to enable access to the `api` from python using pybind. +- Creation of a second python interface using boost (rough first pass) +- cppcheck -Currently only building on windows using `msbuild` has been tested. +Currently only building on windows using `msbuild` and `ninja` has been tested. Instructions to this regard are in the following section. ## Pre-setup requirements - Clone this repository - Ensure `conda` (or preferably `mamba`) is installed. -- Ensure `msbuildtools` are available, and on the path. +## Pre-setup msbuild only -## Setup +- Ensure `msbuildtools` are available, and on the path. These are typically in: `/c/Program Files/Microsoft Visual Studio/2022/Community/MSBuild/Current/Bin` + + +## Setup msbuild 1. From repository root, create conda environment: `conda env create -f environment.yml`. This will create a conda environment called `basic-setup` 2. Activate this conda environment: `conda activate basic-setup`. -3. Run cmake: `cmake --preset windows-default` +3. Run cmake: `cmake --preset win-ninja` -4. From the created `build` folder, run `msbuild`: `msbuild basicSetup.sln` +4. From the created `build` directory, run `msbuild`: `msbuild basicSetup.sln` 5. Add the directory of the created python interface to the python path: `set PYTHONPATH=%PYTHONPATH%;\build\lib\Debug` +## Setup ninja + +1. On windows this setup must be undertaken using `x64 Native Tools Command Prompt for VS 2022`. + +2. From repository root, create conda environment: `conda env create -f environment.yml`. + This will create a conda environment called `basic-setup` + +3. Activate this conda environment: `conda activate basic-setup`. + +4. Run cmake: `cmake --preset win-ninja` + +5. From the created `build` directory, run `ninja` + +6. Add the directory of the created python interface to the python path: `set PYTHONPATH=%PYTHONPATH%;\build\lib` + ## Testing the repo setup -1. To test that the setup has been successfull, from the repository root run: `python -c "from basicSetupApi import helloWorld; helloWorld()"` +1. To test that the setup has been successfull, from the repository root run: `python -c "from basicSetupApi import helloWorld; helloWorld('')"` + +## Running cppcheck + +1. As of the latest version of cppcheck on `conda-forge`, `2.15.0`, there is a bug causing cppcheck to look for `cfg` files in the wrong location: + https://github.com/conda-forge/cppcheck-feedstock/issues/19 + To circumvent this, we must copy the `cfg` directory from `/c/Users//AppData/Local/mambaforge/envs/basic-setup/share/Cppcheck/cfg` to a location on the + path that cppcheck searches: `C:/Users//AppData/Local/mambaforge/envs/basic-setup/Library/bin/cfg` +2. From the `build` directory, run `cmake --build . --target cppcheck` diff --git a/api/CMakeLists.txt b/api/CMakeLists.txt index 8bf0f74..fd5d14a 100644 --- a/api/CMakeLists.txt +++ b/api/CMakeLists.txt @@ -14,11 +14,11 @@ pybind11_add_module(basicSetupApi ${CMAKE_CURRENT_SOURCE_DIR}/pythonInterface/ap target_link_libraries(basicSetupApi PRIVATE api) ### Boost Python API -find_package(Boost REQUIRED COMPONENTS python313) +find_package(Boost REQUIRED COMPONENTS python312) find_package(Python3 REQUIRED COMPONENTS Interpreter Development) # Create boost api library add_library(api_boost MODULE ${CMAKE_CURRENT_SOURCE_DIR}/pythonInterface/apiBindingsBoost.cpp) target_include_directories(api_boost PRIVATE ${Boost_INCLUDE_DIRS} ${Python3_INCLUDE_DIRS}) -target_link_libraries(api_boost PRIVATE Boost::boost Boost::python313 ${Python3_LIBRARIES}) +target_link_libraries(api_boost PRIVATE Boost::boost Boost::python312 ${Python3_LIBRARIES}) set_target_properties(api_boost PROPERTIES PREFIX "" SUFFIX ".pyd") \ No newline at end of file diff --git a/api/pythonInterface/apiBindingsBoost.cpp b/api/pythonInterface/apiBindingsBoost.cpp index 092b744..b540fff 100644 --- a/api/pythonInterface/apiBindingsBoost.cpp +++ b/api/pythonInterface/apiBindingsBoost.cpp @@ -13,7 +13,7 @@ class ComplexNumber { const double getImaginary() const { return m_imaginary; } ComplexNumber ComplexNumber::operator+(const ComplexNumber& rhs) { return ComplexNumber(m_real + rhs.getReal(), m_imaginary + rhs.getImaginary()); } - void print() { std::cout << m_real << ", " << m_imaginary; } + void print() { std::cout << m_real << " + " << m_imaginary << "i"; } }; diff --git a/environment.yml b/environment.yml index 49f5acb..efcc622 100644 --- a/environment.yml +++ b/environment.yml @@ -1,8 +1,10 @@ name: basic-setup dependencies: - - python + - python==3.12 - pybind11 - cmake - libboost-devel - libboost-python-devel + - cppcheck==2.15.0 + - ninja From 132003539dc1c26ea828390d1200d74957ff99a7 Mon Sep 17 00:00:00 2001 From: MialLewis <95620982+MialLewis@users.noreply.github.com> Date: Thu, 30 Jan 2025 12:46:39 +0000 Subject: [PATCH 5/7] add sub --- api/pythonInterface/apiBindingsBoost.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/pythonInterface/apiBindingsBoost.cpp b/api/pythonInterface/apiBindingsBoost.cpp index b540fff..260acaa 100644 --- a/api/pythonInterface/apiBindingsBoost.cpp +++ b/api/pythonInterface/apiBindingsBoost.cpp @@ -13,6 +13,7 @@ class ComplexNumber { const double getImaginary() const { return m_imaginary; } ComplexNumber ComplexNumber::operator+(const ComplexNumber& rhs) { return ComplexNumber(m_real + rhs.getReal(), m_imaginary + rhs.getImaginary()); } + ComplexNumber ComplexNumber::operator-(const ComplexNumber& rhs) { return ComplexNumber(m_real - rhs.getReal(), m_imaginary - rhs.getImaginary()); } void print() { std::cout << m_real << " + " << m_imaginary << "i"; } }; @@ -27,6 +28,7 @@ BOOST_PYTHON_MODULE(api_boost) { def("add", add); class_("ComplexNumber", init()) + .def("__sub__", &ComplexNumber::operator-, (arg("left"), arg("right"))) .def("__add__", &ComplexNumber::operator+, (arg("left"), arg("right"))) .def("print", &ComplexNumber::print); } From 9bffad45fade6c8002eb3e31348ec383a9c8d1b6 Mon Sep 17 00:00:00 2001 From: MialLewis <95620982+MialLewis@users.noreply.github.com> Date: Thu, 30 Jan 2025 14:37:11 +0000 Subject: [PATCH 6/7] fix cppcheck warnings --- CMakeLists.txt | 1 + README.md | 2 ++ api/inc/basicSetupApi/helloWorld.h | 2 +- api/pythonInterface/apiBindingsBoost.cpp | 16 +++++++++++----- kernel/inc/basicSetupKernel/printer.h | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 885939b..9693825 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ set(CPPCHECK_ARGS --std=c++${CMAKE_CXX_STANDARD} # use the standard from cmake --cppcheck-build-dir="${CPPCHECK_BUILD_DIR}/cache" --project="${CMAKE_BINARY_DIR}/compile_commands.json" + --suppress=missingIncludeSystem ) if(CPPCHECK_EXECUTABLE) diff --git a/README.md b/README.md index 35a1d86..3dddc5f 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Instructions to this regard are in the following section. 1. To test that the setup has been successfull, from the repository root run: `python -c "from basicSetupApi import helloWorld; helloWorld('')"` +2. Alternatively (for boost api): `python -c "from api_boost import ComplexNumber; (ComplexNumber(2,5) + ComplexNumber(3,4)).print()"` + ## Running cppcheck 1. As of the latest version of cppcheck on `conda-forge`, `2.15.0`, there is a bug causing cppcheck to look for `cfg` files in the wrong location: diff --git a/api/inc/basicSetupApi/helloWorld.h b/api/inc/basicSetupApi/helloWorld.h index d89c379..0850562 100644 --- a/api/inc/basicSetupApi/helloWorld.h +++ b/api/inc/basicSetupApi/helloWorld.h @@ -5,7 +5,7 @@ namespace basicSetup::api{ class helloWorld{ public: helloWorld(); - helloWorld(const std::string &name); + explicit helloWorld(const std::string &name); private: void _print(const std::string &name = "") const; diff --git a/api/pythonInterface/apiBindingsBoost.cpp b/api/pythonInterface/apiBindingsBoost.cpp index 260acaa..993e967 100644 --- a/api/pythonInterface/apiBindingsBoost.cpp +++ b/api/pythonInterface/apiBindingsBoost.cpp @@ -12,9 +12,15 @@ class ComplexNumber { const double getReal() const { return m_real; } const double getImaginary() const { return m_imaginary; } - ComplexNumber ComplexNumber::operator+(const ComplexNumber& rhs) { return ComplexNumber(m_real + rhs.getReal(), m_imaginary + rhs.getImaginary()); } - ComplexNumber ComplexNumber::operator-(const ComplexNumber& rhs) { return ComplexNumber(m_real - rhs.getReal(), m_imaginary - rhs.getImaginary()); } - void print() { std::cout << m_real << " + " << m_imaginary << "i"; } + ComplexNumber ComplexNumber::operator+(const ComplexNumber& rhs) { + std::cout << "operator+ executed" << std::endl; + return ComplexNumber(m_real + rhs.getReal(), m_imaginary + rhs.getImaginary()); + } + ComplexNumber ComplexNumber::operator-(const ComplexNumber& rhs) { + std::cout << "operator- executed" << std::endl; + return ComplexNumber(m_real - rhs.getReal(), m_imaginary - rhs.getImaginary()); + } + void print() const { std::cout << m_real << " + " << m_imaginary << "i"; } }; @@ -28,7 +34,7 @@ BOOST_PYTHON_MODULE(api_boost) { def("add", add); class_("ComplexNumber", init()) - .def("__sub__", &ComplexNumber::operator-, (arg("left"), arg("right"))) - .def("__add__", &ComplexNumber::operator+, (arg("left"), arg("right"))) + .def(self - self) + .def(self + self) .def("print", &ComplexNumber::print); } diff --git a/kernel/inc/basicSetupKernel/printer.h b/kernel/inc/basicSetupKernel/printer.h index e16fc3b..45aa03f 100644 --- a/kernel/inc/basicSetupKernel/printer.h +++ b/kernel/inc/basicSetupKernel/printer.h @@ -5,7 +5,7 @@ namespace basicSetup::kernel{ class printer{ public: - printer(const std::string &str); + explicit printer(const std::string &str); private: void _print(const std::string &str) const; From e88c43b26060361a587add61db7dff49bc303832 Mon Sep 17 00:00:00 2001 From: MialLewis <95620982+MialLewis@users.noreply.github.com> Date: Thu, 30 Jan 2025 15:08:53 +0000 Subject: [PATCH 7/7] remove whitelines --- CMakeLists.txt | 1 - api/pythonInterface/apiBindingsBoost.cpp | 2 -- 2 files changed, 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9693825..290be4f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,6 @@ add_executable(basicSetup main.cpp) target_link_libraries(basicSetup PUBLIC kernel api) # Set up cppcheck - # Set up cppcheck build directory and cache set(CPPCHECK_BUILD_DIR "${CMAKE_BINARY_DIR}/cppcheck") file(MAKE_DIRECTORY "${CPPCHECK_BUILD_DIR}" "${CPPCHECK_BUILD_DIR}/cache") diff --git a/api/pythonInterface/apiBindingsBoost.cpp b/api/pythonInterface/apiBindingsBoost.cpp index 993e967..1d17c83 100644 --- a/api/pythonInterface/apiBindingsBoost.cpp +++ b/api/pythonInterface/apiBindingsBoost.cpp @@ -23,8 +23,6 @@ class ComplexNumber { void print() const { std::cout << m_real << " + " << m_imaginary << "i"; } }; - - int add(int a, int b) { return a + b; }