├── .github └── workflows │ ├── binder.yml │ ├── sphinx.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── apt.txt ├── content ├── _static │ └── overrides.css ├── bibliography.bib ├── cmake-syntax.rst ├── code │ ├── LICENSE │ ├── day-1 │ │ ├── 00_hello-cxx │ │ │ ├── hello.cpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── hello.cpp │ │ ├── 00_hello-f │ │ │ ├── hello.f90 │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── hello.f90 │ │ ├── 01_libraries-cxx │ │ │ ├── CMakeLists.txt │ │ │ ├── Message.cpp │ │ │ ├── Message.hpp │ │ │ ├── hello-world.cpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── Message.cpp │ │ │ │ ├── Message.hpp │ │ │ │ └── hello-world.cpp │ │ ├── 01_libraries-f │ │ │ ├── CMakeLists.txt │ │ │ ├── hello-world.f90 │ │ │ ├── message.f90 │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── hello-world.f90 │ │ │ │ └── message.f90 │ │ ├── 02_conditionals-cxx │ │ │ ├── Message.cpp │ │ │ ├── Message.hpp │ │ │ ├── hello-world.cpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── Message.cpp │ │ │ │ ├── Message.hpp │ │ │ │ └── hello-world.cpp │ │ ├── 02_conditionals-f │ │ │ ├── hello-world.f90 │ │ │ ├── message.f90 │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── hello-world.f90 │ │ │ │ └── message.f90 │ │ ├── 03_loops-cxx │ │ │ ├── compute-areas.cpp │ │ │ ├── geometry_circle.cpp │ │ │ ├── geometry_circle.hpp │ │ │ ├── geometry_polygon.cpp │ │ │ ├── geometry_polygon.hpp │ │ │ ├── geometry_rhombus.cpp │ │ │ ├── geometry_rhombus.hpp │ │ │ ├── geometry_square.cpp │ │ │ ├── geometry_square.hpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── compute-areas.cpp │ │ │ │ ├── geometry_circle.cpp │ │ │ │ ├── geometry_circle.hpp │ │ │ │ ├── geometry_polygon.cpp │ │ │ │ ├── geometry_polygon.hpp │ │ │ │ ├── geometry_rhombus.cpp │ │ │ │ ├── geometry_rhombus.hpp │ │ │ │ ├── geometry_square.cpp │ │ │ │ └── geometry_square.hpp │ │ ├── 04_options-cxx │ │ │ ├── CMakeLists.txt │ │ │ ├── Message.cpp │ │ │ ├── Message.hpp │ │ │ ├── hello-world.cpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── Message.cpp │ │ │ │ ├── Message.hpp │ │ │ │ └── hello-world.cpp │ │ ├── 04_options-f │ │ │ ├── CMakeLists.txt │ │ │ ├── hello-world.f90 │ │ │ ├── message.f90 │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── hello-world.f90 │ │ │ │ └── message.f90 │ │ ├── 05_hello-ctest │ │ │ ├── main.cpp │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── main.cpp │ │ │ │ ├── sum_integers.cpp │ │ │ │ ├── sum_integers.hpp │ │ │ │ └── test.cpp │ │ │ ├── sum_integers.cpp │ │ │ ├── sum_integers.hpp │ │ │ └── test.cpp │ │ ├── 06_bash-ctest │ │ │ ├── CMakeLists.txt │ │ │ ├── main.cpp │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── main.cpp │ │ │ │ ├── sum_integers.cpp │ │ │ │ ├── sum_integers.hpp │ │ │ │ ├── test.cpp │ │ │ │ └── test.sh │ │ │ ├── sum_integers.cpp │ │ │ ├── sum_integers.hpp │ │ │ ├── test.cpp │ │ │ └── test.sh │ │ ├── 07_python-ctest │ │ │ ├── CMakeLists.txt │ │ │ ├── main.cpp │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── main.cpp │ │ │ │ ├── sum_integers.cpp │ │ │ │ ├── sum_integers.hpp │ │ │ │ ├── test.cpp │ │ │ │ ├── test.py │ │ │ │ └── test.sh │ │ │ ├── sum_integers.cpp │ │ │ ├── sum_integers.hpp │ │ │ ├── test.cpp │ │ │ ├── test.py │ │ │ └── test.sh │ │ ├── 08_ctest-labels │ │ │ ├── CMakeLists.txt │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── test │ │ │ │ │ ├── benchmark-a.py │ │ │ │ │ ├── benchmark-b.py │ │ │ │ │ ├── feature-a.py │ │ │ │ │ ├── feature-b.py │ │ │ │ │ ├── feature-c.py │ │ │ │ │ └── feature-d.py │ │ │ └── test │ │ │ │ ├── benchmark-a.py │ │ │ │ ├── benchmark-b.py │ │ │ │ ├── feature-a.py │ │ │ │ ├── feature-b.py │ │ │ │ ├── feature-c.py │ │ │ │ └── feature-d.py │ │ ├── 09_ctest-will-fail │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── test.py │ │ │ └── test.py │ │ ├── 10_ctest-cost │ │ │ ├── CMakeLists.txt │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── test │ │ │ │ │ ├── a.py │ │ │ │ │ ├── b.py │ │ │ │ │ ├── c.py │ │ │ │ │ ├── d.py │ │ │ │ │ ├── e.py │ │ │ │ │ ├── f.py │ │ │ │ │ ├── g.py │ │ │ │ │ ├── h.py │ │ │ │ │ ├── i.py │ │ │ │ │ └── j.py │ │ │ └── test │ │ │ │ ├── a.py │ │ │ │ ├── b.py │ │ │ │ ├── c.py │ │ │ │ ├── d.py │ │ │ │ ├── e.py │ │ │ │ ├── f.py │ │ │ │ ├── g.py │ │ │ │ ├── h.py │ │ │ │ ├── i.py │ │ │ │ └── j.py │ │ ├── 11_ctest-timeout │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── test.py │ │ │ └── test.py │ │ ├── 12_OS │ │ │ └── solution │ │ │ │ └── CMakeLists.txt │ │ ├── 13_processor │ │ │ ├── CMakeLists.txt │ │ │ └── solution │ │ │ │ └── CMakeLists.txt │ │ ├── 14_host_system_information │ │ │ ├── CMakeLists.txt │ │ │ └── solution │ │ │ │ └── CMakeLists.txt │ │ ├── 15_sys_preproc │ │ │ ├── CMakeLists.txt │ │ │ ├── hello-world.cpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── hello-world.cpp │ │ ├── 16_configure │ │ │ ├── CMakeLists.txt │ │ │ ├── config.h.in │ │ │ ├── processor-info.cpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── config.h.in │ │ │ │ └── processor-info.cpp │ │ ├── 17_find_cffi │ │ │ ├── CMakeLists.txt │ │ │ └── solution │ │ │ │ └── CMakeLists.txt │ │ ├── 18_pre_post-f │ │ │ ├── CMakeLists.txt │ │ │ ├── echo-file.py │ │ │ ├── example.f90 │ │ │ ├── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── echo-file.py │ │ │ │ ├── example.f90 │ │ │ │ └── static-size.py │ │ │ └── static-size.py │ │ ├── 19_check_compiler_flag │ │ │ ├── CMakeLists.txt │ │ │ ├── asan-example.cpp │ │ │ └── solution │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── asan-example.cpp │ │ └── 20_check_source_runs │ │ │ ├── CMakeLists.txt │ │ │ ├── solution │ │ │ ├── CMakeLists.txt │ │ │ └── use-uuid.cpp │ │ │ └── use-uuid.cpp │ └── day-2 │ │ ├── 21_automata-cxx │ │ ├── CMakeLists.txt │ │ ├── external │ │ │ ├── CMakeLists.txt │ │ │ ├── conversion.cpp │ │ │ └── conversion.hpp │ │ ├── solution │ │ │ ├── CMakeLists.txt │ │ │ ├── external │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── conversion.cpp │ │ │ │ └── conversion.hpp │ │ │ └── src │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── evolution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── evolution.cpp │ │ │ │ └── evolution.hpp │ │ │ │ ├── initial │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── initial.cpp │ │ │ │ └── initial.hpp │ │ │ │ ├── io │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── io.cpp │ │ │ │ └── io.hpp │ │ │ │ ├── main.cpp │ │ │ │ └── parser │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── parser.cpp │ │ │ │ └── parser.hpp │ │ └── src │ │ │ ├── CMakeLists.txt │ │ │ ├── evolution │ │ │ ├── CMakeLists.txt │ │ │ ├── evolution.cpp │ │ │ └── evolution.hpp │ │ │ ├── initial │ │ │ ├── CMakeLists.txt │ │ │ ├── initial.cpp │ │ │ └── initial.hpp │ │ │ ├── io │ │ │ ├── CMakeLists.txt │ │ │ ├── io.cpp │ │ │ └── io.hpp │ │ │ ├── main.cpp │ │ │ └── parser │ │ │ ├── CMakeLists.txt │ │ │ ├── parser.cpp │ │ │ └── parser.hpp │ │ ├── 21_automata-f │ │ ├── CMakeLists.txt │ │ ├── external │ │ │ ├── CMakeLists.txt │ │ │ └── conversion.f90 │ │ ├── solution │ │ │ ├── CMakeLists.txt │ │ │ ├── external │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── conversion.f90 │ │ │ └── src │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── evolution │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── ancestors.f90 │ │ │ │ ├── empty.f90 │ │ │ │ └── evolution.f90 │ │ │ │ ├── initial │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── initial.f90 │ │ │ │ ├── io │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── io.f90 │ │ │ │ ├── main.f90 │ │ │ │ └── parser │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── parser.f90 │ │ └── src │ │ │ ├── CMakeLists.txt │ │ │ ├── evolution │ │ │ ├── CMakeLists.txt │ │ │ ├── ancestors.f90 │ │ │ ├── empty.f90 │ │ │ └── evolution.f90 │ │ │ ├── initial │ │ │ ├── CMakeLists.txt │ │ │ └── initial.f90 │ │ │ ├── io │ │ │ ├── CMakeLists.txt │ │ │ └── io.f90 │ │ │ ├── main.f90 │ │ │ └── parser │ │ │ ├── CMakeLists.txt │ │ │ └── parser.f90 │ │ ├── 22_taskloop │ │ └── solution │ │ │ ├── CMakeLists.txt │ │ │ └── taskloop.cpp │ │ ├── 23_mpi-cxx │ │ ├── CMakeLists.txt │ │ ├── hello-mpi.cpp │ │ └── solution │ │ │ ├── CMakeLists.txt │ │ │ └── hello-mpi.cpp │ │ ├── 23_mpi-f │ │ ├── CMakeLists.txt │ │ ├── hello-mpi.f90 │ │ └── solution │ │ │ ├── CMakeLists.txt │ │ │ └── hello-mpi.f90 │ │ ├── 24_fortran-cxx │ │ ├── CMakeLists.txt │ │ ├── solution │ │ │ ├── CMakeLists.txt │ │ │ └── src │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── bt-randomgen-example.f90 │ │ │ │ ├── interfaces │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── interface_backtrace.f90 │ │ │ │ ├── interface_randomgen.f90 │ │ │ │ └── randomgen.cpp │ │ │ │ └── utils │ │ │ │ ├── CMakeLists.txt │ │ │ │ └── util_strings.f90 │ │ └── src │ │ │ ├── CMakeLists.txt │ │ │ ├── bt-randomgen-example.f90 │ │ │ ├── interfaces │ │ │ ├── CMakeLists.txt │ │ │ ├── interface_backtrace.f90 │ │ │ ├── interface_randomgen.f90 │ │ │ └── randomgen.cpp │ │ │ └── utils │ │ │ ├── CMakeLists.txt │ │ │ └── util_strings.f90 │ │ ├── 25_cxx-fortran │ │ ├── CMakeLists.txt │ │ ├── solution │ │ │ ├── CMakeLists.txt │ │ │ └── src │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── linear-algebra.cpp │ │ │ │ └── math │ │ │ │ ├── CMakeLists.txt │ │ │ │ ├── CxxBLAS.cpp │ │ │ │ ├── CxxBLAS.hpp │ │ │ │ ├── CxxLAPACK.cpp │ │ │ │ └── CxxLAPACK.hpp │ │ └── src │ │ │ ├── CMakeLists.txt │ │ │ ├── linear-algebra.cpp │ │ │ └── math │ │ │ ├── CMakeLists.txt │ │ │ ├── CxxBLAS.cpp │ │ │ ├── CxxBLAS.hpp │ │ │ ├── CxxLAPACK.cpp │ │ │ └── CxxLAPACK.hpp │ │ ├── 26_more-catch2 │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ ├── solution │ │ │ ├── CMakeLists.txt │ │ │ ├── main.cpp │ │ │ ├── sum_integers.cpp │ │ │ ├── sum_integers.hpp │ │ │ └── test.cpp │ │ ├── sum_integers.cpp │ │ ├── sum_integers.hpp │ │ └── test.cpp │ │ ├── 27_cxx-pybind11 │ │ ├── account │ │ │ ├── CMakeLists.txt │ │ │ ├── account.cpp │ │ │ ├── account.hpp │ │ │ └── test.py │ │ └── solution │ │ │ ├── CMakeLists.txt │ │ │ └── account │ │ │ ├── CMakeLists.txt │ │ │ ├── account.cpp │ │ │ ├── account.hpp │ │ │ └── test.py │ │ ├── 28_cxx-cffi │ │ ├── CMakeLists.txt │ │ ├── account │ │ │ ├── CMakeLists.txt │ │ │ ├── __init__.py │ │ │ ├── account.cpp │ │ │ ├── account.h │ │ │ ├── account.hpp │ │ │ ├── c_cpp_interface.cpp │ │ │ ├── cffi_builder.py │ │ │ └── test.py │ │ └── solution │ │ │ ├── CMakeLists.txt │ │ │ └── account │ │ │ ├── CMakeLists.txt │ │ │ ├── __init__.py │ │ │ ├── account.cpp │ │ │ ├── account.h │ │ │ ├── account.hpp │ │ │ ├── c_cpp_interface.cpp │ │ │ ├── cffi_builder.py │ │ │ └── test.py │ │ ├── 28_fortran-cffi │ │ ├── CMakeLists.txt │ │ ├── account │ │ │ ├── CMakeLists.txt │ │ │ ├── __init__.py │ │ │ ├── account.f90 │ │ │ ├── account.h │ │ │ ├── cffi_builder.py │ │ │ └── test.py │ │ └── solution │ │ │ ├── CMakeLists.txt │ │ │ └── account │ │ │ ├── CMakeLists.txt │ │ │ ├── __init__.py │ │ │ ├── account.f90 │ │ │ ├── account.h │ │ │ ├── cffi_builder.py │ │ │ └── test.py │ │ └── 29_visibility-levels │ │ └── solution │ │ ├── CMakeLists.txt │ │ ├── account │ │ ├── CMakeLists.txt │ │ ├── account.cpp │ │ └── account.hpp │ │ └── bank.cpp ├── conf.py ├── custom.py ├── cxx-fortran.rst ├── dependencies.rst ├── diagrams │ ├── cmake.drawio │ ├── ctest.drawio │ └── targets.drawio ├── environment.rst ├── fetch-content.rst ├── guide.rst ├── hello-cmake.rst ├── hello-ctest.rst ├── img │ ├── ENCCS.jpg │ ├── binder_landing_page.png │ ├── binder_loading.png │ ├── build-systems.svg │ ├── cmake-times.jpg │ ├── ctest.svg │ ├── favicon.ico │ ├── launch_binder_button.png │ ├── open_terminal_in_binder.png │ ├── project.svg │ ├── target.svg │ ├── target_inheritance.svg │ └── terminal_and_contents.png ├── index.rst ├── probing.rst ├── python-bindings.rst ├── quick-reference.rst ├── setup.rst ├── targets.rst ├── tips-and-tricks.rst └── zbibliography.rst ├── environment.yml ├── make.bat └── requirements.txt /.github/workflows/binder.yml: -------------------------------------------------------------------------------- 1 | name: Build Notebook Container 2 | 3 | on: 4 | push: 5 | workflow_dispatch: 6 | 7 | concurrency: 8 | group: latest-repo2docker-group 9 | cancel-in-progress: true 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | name: Run repo2docker 15 | steps: 16 | 17 | - name: checkout files in repo 18 | uses: actions/checkout@v2 19 | 20 | - name: update jupyter dependencies with repo2docker 21 | uses: jupyterhub/repo2docker-action@master 22 | with: 23 | DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} 24 | DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} 25 | DOCKER_REGISTRY: ghcr.io 26 | MYBINDERORG_TAG: ${{ github.event.ref }} 27 | PUBLIC_REGISTRY_CHECK: true 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /_build 2 | .ipynb_checkpoints 3 | /venv* 4 | .jupyter_cache 5 | jupyter_execute 6 | /content/__pycache__/ 7 | /.ccls-cache/ 8 | /content/.auctex-auto/ 9 | /content/code/*/*/build* 10 | /content/code/*/*/solution/build* 11 | /.direnv/ 12 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = content 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/ENCCS/cmake-workshop/HEAD) 2 | 3 | # CMake 4 | 5 | ## Credit and license 6 | 7 | - https://enccs.github.io/cmake-workshop/#credits 8 | -------------------------------------------------------------------------------- /apt.txt: -------------------------------------------------------------------------------- 1 | emacs-nox 2 | nano 3 | tree 4 | vim-nox 5 | -------------------------------------------------------------------------------- /content/_static/overrides.css: -------------------------------------------------------------------------------- 1 | /* 2 | * colors = ['#0271AE', '#DC2830', '#FFC438', # blue, red, light orange 3 | * '#6E3B87', '#008D5D', '#FA902D', # purple, green, orange 4 | * '#0095B7', '#CB0C7B', '#F7E43C', # cyan, magenta, yellow 5 | * '#88B93B', '#444F95', '#F16232'] # pea green, dark blue, dark orange 6 | * 7 | * To use them in rST, you need to define a command in the epilog, see conf.py 8 | */ 9 | .blue {color: #0271AE;} 10 | .red {color: #DC2830;} 11 | .orange {color: #FFC438;} 12 | .purple {color: #633B87;} 13 | .green {color: #008D5D;} 14 | .dkorange {color: #FA902D;} 15 | .cyan {color: #0095B7;} 16 | .magenta {color: #CB0C8B;} 17 | .yellow {color: #F7E43C;} 18 | .peagreen {color: #88B93B;} 19 | .darkblue {color: #444F95;} 20 | .darkorange {color: #F16232;} 21 | 22 | /* override colors in sphinx_lesson.css with the schemes here: https://personal.sron.nl/~pault/#sec:qualitative */ 23 | 24 | /* instructor-note */ 25 | .rst-content .instructor-note { 26 | background: #DDDDDD; 27 | } 28 | .rst-content .instructor-note > .admonition-title { 29 | background: #BBBBBB; 30 | } 31 | .rst-content .instructor-note > .admonition-title::before { 32 | content: ""; 33 | } 34 | 35 | /* callout */ 36 | .rst-content .callout { 37 | background: #EEEEBB; 38 | } 39 | .rst-content .callout > .admonition-title { 40 | background: #BBCC33; 41 | } 42 | 43 | /* questions */ 44 | .rst-content .questions { 45 | background: rgba(253, 219, 199, 0.3); 46 | } 47 | .rst-content .questions > .admonition-title { 48 | background: rgba(204, 51, 17, 0.5); 49 | } 50 | 51 | /* discussion */ 52 | .rst-content .discussion { 53 | background: rgba(231, 212, 232 0.3); 54 | } 55 | .rst-content .discussion > .admonition-title { 56 | background: rgba(194, 165, 207, 0.5); 57 | } 58 | 59 | /* signature */ 60 | .rst-content .signature { 61 | background: rgba(217, 240, 211, 0.3); 62 | } 63 | .rst-content .signature > .admonition-title { 64 | background: rgba(172, 211, 158, 0.5); 65 | } 66 | .rst-content .signature > .admonition-title::before { 67 | content: "\01F527"; 68 | } 69 | 70 | /* parameters */ 71 | .rst-content .parameters { 72 | background: rgba(217, 240, 211, 0.0); 73 | } 74 | .rst-content .parameters > .admonition-title { 75 | background: rgba(172, 211, 158, 0.5); 76 | } 77 | .rst-content .parameters > .admonition-title::before { 78 | content: "\01F4BB"; 79 | } 80 | 81 | /* typealong */ 82 | .rst-content .typealong { 83 | background: rgba(221, 221, 221, 0.3); 84 | } 85 | .rst-content .typealong > .admonition-title { 86 | background: rgba(187, 187, 187, 1.0); 87 | } 88 | .rst-content .typealong > .admonition-title::before { 89 | content: "\02328"; 90 | } 91 | 92 | /* Equation numbers to the right */ 93 | .math { 94 | text-align: left; 95 | } 96 | .eqno { 97 | float: right; 98 | } 99 | -------------------------------------------------------------------------------- /content/bibliography.bib: -------------------------------------------------------------------------------- 1 | @BOOK{Bast2018-pq, 2 | title = "{CMake Cookbook: Building, testing, and packaging modular 3 | software with modern CMake}", 4 | author = "Bast, Radovan and Di Remigio, Roberto", 5 | publisher = "Packt Publishing", 6 | month = sep, 7 | year = 2018, 8 | url = "https://www.packtpub.com/application-development/cmake-cookbook", 9 | language = "en", 10 | isbn = "9781788470711" 11 | } 12 | -------------------------------------------------------------------------------- /content/code/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 EuroCC National Competence Center Sweden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /content/code/day-1/00_hello-cxx/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::cout << "Hello world" << std::endl; 6 | 7 | return EXIT_SUCCESS; 8 | } 9 | -------------------------------------------------------------------------------- /content/code/day-1/00_hello-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(Hello LANGUAGES CXX) 4 | 5 | add_executable(hello hello.cpp) 6 | -------------------------------------------------------------------------------- /content/code/day-1/00_hello-cxx/solution/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::cout << "Hello world" << std::endl; 6 | 7 | return EXIT_SUCCESS; 8 | } 9 | -------------------------------------------------------------------------------- /content/code/day-1/00_hello-f/hello.f90: -------------------------------------------------------------------------------- 1 | pure function say_hello() result(message) 2 | 3 | implicit none 4 | 5 | character(len=11) :: message 6 | 7 | message = 'Hello world' 8 | 9 | end function 10 | 11 | program hello_world 12 | 13 | implicit none 14 | 15 | character(len=11) :: say_hello 16 | 17 | print *, say_hello() 18 | 19 | end program 20 | -------------------------------------------------------------------------------- /content/code/day-1/00_hello-f/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(Hello LANGUAGES Fortran) 4 | 5 | add_executable(hello hello.f90) 6 | -------------------------------------------------------------------------------- /content/code/day-1/00_hello-f/solution/hello.f90: -------------------------------------------------------------------------------- 1 | pure function say_hello() result(message) 2 | 3 | implicit none 4 | 5 | character(len=11) :: message 6 | 7 | message = 'Hello world' 8 | 9 | end function 10 | 11 | program hello_world 12 | 13 | implicit none 14 | 15 | character(len=11) :: say_hello 16 | 17 | print *, say_hello() 18 | 19 | end program 20 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME set minimum cmake version 2 | cmake_minimum_required(...) 3 | 4 | # FIXME declare project giving project name and language 5 | project(... LANGUAGES ...) 6 | 7 | # FIXME create the message library from the source files 8 | add_library(...) 9 | 10 | # FIXME create hello-world executable from hello-world.cpp 11 | add_executable(hello-world ...) 12 | 13 | # FIXME link hello-world to the message library 14 | target_link_libraries(hello-world ...) 15 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::ostream &Message::printObject(std::ostream &os) { 7 | os << "This is my very nice message: " << std::endl; 8 | os << message_; 9 | 10 | return os; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/Message.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Message { 7 | public: 8 | Message(const std::string &m) : message_(m) {} 9 | 10 | friend std::ostream &operator<<(std::ostream &os, Message &obj) { 11 | return obj.printObject(os); 12 | } 13 | 14 | private: 15 | std::string message_; 16 | std::ostream &printObject(std::ostream &os); 17 | }; 18 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | Message say_hello("Hello, CMake World!"); 8 | 9 | std::cout << say_hello << std::endl; 10 | 11 | Message say_goodbye("Goodbye, CMake World"); 12 | 13 | std::cout << say_goodbye << std::endl; 14 | 15 | return EXIT_SUCCESS; 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(libraries LANGUAGES CXX) 6 | 7 | # generate a library from sources 8 | add_library(message 9 | Message.hpp 10 | Message.cpp 11 | ) 12 | 13 | add_executable(hello-world hello-world.cpp) 14 | 15 | target_link_libraries(hello-world PRIVATE message) 16 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/solution/Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::ostream &Message::printObject(std::ostream &os) { 7 | os << "This is my very nice message: " << std::endl; 8 | os << message_; 9 | 10 | return os; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/solution/Message.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Message { 7 | public: 8 | Message(const std::string &m) : message_(m) {} 9 | 10 | friend std::ostream &operator<<(std::ostream &os, Message &obj) { 11 | return obj.printObject(os); 12 | } 13 | 14 | private: 15 | std::string message_; 16 | std::ostream &printObject(std::ostream &os); 17 | }; 18 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-cxx/solution/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | Message say_hello("Hello, CMake World!"); 8 | 9 | std::cout << say_hello << std::endl; 10 | 11 | Message say_goodbye("Goodbye, CMake World"); 12 | 13 | std::cout << say_goodbye << std::endl; 14 | 15 | return EXIT_SUCCESS; 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-f/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME set minimum cmake version 2 | cmake_minimum_required(...) 3 | 4 | # FIXME declare project giving project name and language 5 | project(... LANGUAGES ...) 6 | 7 | # FIXME create the message library from the message.f90 source file 8 | add_library(...) 9 | 10 | # FIXME create hello-world executable from hello-world.f90 11 | add_executable(hello-world ...) 12 | 13 | # FIXME link hello-world to the message library 14 | target_link_libraries(hello-world ...) 15 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-f/hello-world.f90: -------------------------------------------------------------------------------- 1 | program hello_world 2 | 3 | use messaging 4 | 5 | implicit none 6 | 7 | type(Messenger) :: hello, bye 8 | 9 | hello%message_ = 'Hello, CMake world!' 10 | print *, print_message(hello) 11 | 12 | bye%message_ = 'Bye, CMake world!' 13 | print *, print_message(bye) 14 | 15 | end program 16 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-f/message.f90: -------------------------------------------------------------------------------- 1 | module messaging 2 | 3 | implicit none 4 | 5 | public Messenger 6 | type Messenger 7 | character(len=19) :: message_ 8 | end type 9 | 10 | public print_message 11 | 12 | private 13 | 14 | contains 15 | 16 | pure function print_message(postman) result(m) 17 | 18 | type(Messenger), intent(in) :: postman 19 | character(len=19) :: m 20 | 21 | m = postman%message_ 22 | 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-f/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(libraries LANGUAGES Fortran) 6 | 7 | add_library(message message.f90) 8 | 9 | add_executable(hello-world hello-world.f90) 10 | 11 | target_link_libraries(hello-world PRIVATE message) 12 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-f/solution/hello-world.f90: -------------------------------------------------------------------------------- 1 | program hello_world 2 | 3 | use messaging 4 | 5 | implicit none 6 | 7 | type(Messenger) :: hello, bye 8 | 9 | hello%message_ = 'Hello, CMake world!' 10 | print *, print_message(hello) 11 | 12 | bye%message_ = 'Bye, CMake world!' 13 | print *, print_message(bye) 14 | 15 | end program 16 | -------------------------------------------------------------------------------- /content/code/day-1/01_libraries-f/solution/message.f90: -------------------------------------------------------------------------------- 1 | module messaging 2 | 3 | implicit none 4 | 5 | public Messenger 6 | type Messenger 7 | character(len=19) :: message_ 8 | end type 9 | 10 | public print_message 11 | 12 | private 13 | 14 | contains 15 | 16 | pure function print_message(postman) result(m) 17 | 18 | type(Messenger), intent(in) :: postman 19 | character(len=19) :: m 20 | 21 | m = postman%message_ 22 | 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-cxx/Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::ostream &Message::printObject(std::ostream &os) { 7 | os << "This is my very nice message: " << std::endl; 8 | os << message_; 9 | 10 | return os; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-cxx/Message.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Message { 7 | public: 8 | Message(const std::string &m) : message_(m) {} 9 | 10 | friend std::ostream &operator<<(std::ostream &os, Message &obj) { 11 | return obj.printObject(os); 12 | } 13 | 14 | private: 15 | std::string message_; 16 | std::ostream &printObject(std::ostream &os); 17 | }; 18 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-cxx/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | Message say_hello("Hello, CMake World!"); 8 | 9 | std::cout << say_hello << std::endl; 10 | 11 | Message say_goodbye("Goodbye, CMake World"); 12 | 13 | std::cout << say_goodbye << std::endl; 14 | 15 | return EXIT_SUCCESS; 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(conditionals LANGUAGES CXX) 6 | 7 | set(MAKE_SHARED_LIBRARY OFF) 8 | 9 | if(MAKE_SHARED_LIBRARY) 10 | message(STATUS "Build shared library") 11 | add_library(message SHARED) 12 | else() 13 | message(STATUS "Build static library") 14 | add_library(message STATIC) 15 | endif() 16 | 17 | target_sources(message 18 | PUBLIC 19 | Message.hpp 20 | Message.cpp 21 | ) 22 | 23 | add_executable(hello-world hello-world.cpp) 24 | 25 | target_link_libraries(hello-world PRIVATE message) 26 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-cxx/solution/Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::ostream &Message::printObject(std::ostream &os) { 7 | os << "This is my very nice message: " << std::endl; 8 | os << message_; 9 | 10 | return os; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-cxx/solution/Message.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Message { 7 | public: 8 | Message(const std::string &m) : message_(m) {} 9 | 10 | friend std::ostream &operator<<(std::ostream &os, Message &obj) { 11 | return obj.printObject(os); 12 | } 13 | 14 | private: 15 | std::string message_; 16 | std::ostream &printObject(std::ostream &os); 17 | }; 18 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-cxx/solution/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | Message say_hello("Hello, CMake World!"); 8 | 9 | std::cout << say_hello << std::endl; 10 | 11 | Message say_goodbye("Goodbye, CMake World"); 12 | 13 | std::cout << say_goodbye << std::endl; 14 | 15 | return EXIT_SUCCESS; 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-f/hello-world.f90: -------------------------------------------------------------------------------- 1 | program hello_world 2 | 3 | use messaging 4 | 5 | implicit none 6 | 7 | type(Messenger) :: hello, bye 8 | 9 | hello%message_ = 'Hello, CMake world!' 10 | print *, print_message(hello) 11 | 12 | bye%message_ = 'Bye, CMake world!' 13 | print *, print_message(bye) 14 | 15 | end program 16 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-f/message.f90: -------------------------------------------------------------------------------- 1 | module messaging 2 | 3 | implicit none 4 | 5 | public Messenger 6 | type Messenger 7 | character(len=19) :: message_ 8 | end type 9 | 10 | public print_message 11 | 12 | private 13 | 14 | contains 15 | 16 | pure function print_message(postman) result(m) 17 | 18 | type(Messenger), intent(in) :: postman 19 | character(len=19) :: m 20 | 21 | m = postman%message_ 22 | 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-f/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(conditionals LANGUAGES Fortran) 6 | 7 | set(MAKE_SHARED_LIBRARY OFF) 8 | 9 | if(MAKE_SHARED_LIBRARY) 10 | message(STATUS "Build shared library") 11 | add_library(message SHARED message.f90) 12 | else() 13 | message(STATUS "Build static library") 14 | add_library(message STATIC message.f90) 15 | endif() 16 | 17 | add_executable(hello-world hello-world.f90) 18 | 19 | target_link_libraries(hello-world PRIVATE message) 20 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-f/solution/hello-world.f90: -------------------------------------------------------------------------------- 1 | program hello_world 2 | 3 | use messaging 4 | 5 | implicit none 6 | 7 | type(Messenger) :: hello, bye 8 | 9 | hello%message_ = 'Hello, CMake world!' 10 | print *, print_message(hello) 11 | 12 | bye%message_ = 'Bye, CMake world!' 13 | print *, print_message(bye) 14 | 15 | end program 16 | -------------------------------------------------------------------------------- /content/code/day-1/02_conditionals-f/solution/message.f90: -------------------------------------------------------------------------------- 1 | module messaging 2 | 3 | implicit none 4 | 5 | public Messenger 6 | type Messenger 7 | character(len=19) :: message_ 8 | end type 9 | 10 | public print_message 11 | 12 | private 13 | 14 | contains 15 | 16 | pure function print_message(postman) result(m) 17 | 18 | type(Messenger), intent(in) :: postman 19 | character(len=19) :: m 20 | 21 | m = postman%message_ 22 | 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/compute-areas.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_circle.hpp" 2 | #include "geometry_polygon.hpp" 3 | #include "geometry_rhombus.hpp" 4 | #include "geometry_square.hpp" 5 | 6 | #include 7 | #include 8 | 9 | int main() { 10 | using namespace geometry; 11 | 12 | double radius = 2.5293; 13 | double A_circle = area::circle(radius); 14 | std::cout << "A circle of radius " << radius << " has an area of " << A_circle 15 | << std::endl; 16 | 17 | int nSides = 19; 18 | double side = 1.29312; 19 | double A_polygon = area::polygon(nSides, side); 20 | std::cout << "A regular polygon of " << nSides << " sides of length " << side 21 | << " has an area of " << A_polygon << std::endl; 22 | 23 | double d1 = 5.0; 24 | double d2 = 7.8912; 25 | double A_rhombus = area::rhombus(d1, d2); 26 | std::cout << "A rhombus of major diagonal " << d1 << " and minor diagonal " << d2 27 | << " has an area of " << A_rhombus << std::endl; 28 | 29 | double l = 10.0; 30 | double A_square = area::square(l); 31 | std::cout << "A square of side " << l << " has an area of " << A_square 32 | << std::endl; 33 | 34 | return EXIT_SUCCESS; 35 | } 36 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_circle.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_circle.hpp" 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | namespace geometry { 7 | namespace area { 8 | double circle(double radius) { return M_PI * std::pow(radius, 2); } 9 | } // namespace area 10 | } // namespace geometry 11 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_circle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double circle(double area); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_polygon.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_polygon.hpp" 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | namespace geometry { 7 | namespace area { 8 | double polygon(int nSides, double side) { 9 | double perimeter = nSides * side; 10 | double apothem = side / (2.0 * std::tan(M_PI / nSides)); 11 | return (perimeter * apothem) / 2.0; 12 | } 13 | } // namespace area 14 | } // namespace geometry 15 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_polygon.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double polygon(int nSides, double side); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_rhombus.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_rhombus.hpp" 2 | 3 | namespace geometry { 4 | namespace area { 5 | double rhombus(double d1, double d2) { return (d1 * d2) / 2.0; } 6 | } // namespace area 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_rhombus.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double rhombus(double d1, double d2); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_square.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_square.hpp" 2 | 3 | #include 4 | 5 | namespace geometry { 6 | namespace area { 7 | double square(double l) { return std::pow(l, 2); } 8 | } // namespace area 9 | } // namespace geometry 10 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/geometry_square.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double square(double l); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(loops LANGUAGES CXX) 6 | 7 | add_library(geometry 8 | STATIC 9 | geometry_circle.cpp 10 | geometry_circle.hpp 11 | geometry_polygon.cpp 12 | geometry_polygon.hpp 13 | geometry_rhombus.cpp 14 | geometry_rhombus.hpp 15 | geometry_square.cpp 16 | geometry_square.hpp 17 | ) 18 | 19 | # we wish to compile the library with the optimization flag: -O3 20 | target_compile_options(geometry 21 | PRIVATE 22 | -O3 23 | ) 24 | 25 | list( 26 | APPEND sources_with_lower_optimization 27 | geometry_circle.cpp 28 | geometry_rhombus.cpp 29 | ) 30 | 31 | # we use the IN LISTS foreach syntax to set source properties 32 | message(STATUS "Setting source properties using IN LISTS syntax:") 33 | foreach(_source IN LISTS sources_with_lower_optimization) 34 | set_source_files_properties(${_source} PROPERTIES COMPILE_FLAGS -O2) 35 | message(STATUS "Appending -O2 flag for ${_source}") 36 | endforeach() 37 | 38 | # we demonstrate the plain foreach syntax to query source properties 39 | # which requires to expand the contents of the variable 40 | message(STATUS "Querying sources properties using plain syntax:") 41 | foreach(_source ${sources_with_lower_optimization}) 42 | get_source_file_property(_flags ${_source} COMPILE_FLAGS) 43 | message(STATUS "Source ${_source} has the following extra COMPILE_FLAGS: ${_flags}") 44 | endforeach() 45 | 46 | add_executable(compute-areas compute-areas.cpp) 47 | 48 | target_link_libraries(compute-areas PRIVATE geometry) 49 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/compute-areas.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_circle.hpp" 2 | #include "geometry_polygon.hpp" 3 | #include "geometry_rhombus.hpp" 4 | #include "geometry_square.hpp" 5 | 6 | #include 7 | #include 8 | 9 | int main() { 10 | using namespace geometry; 11 | 12 | double radius = 2.5293; 13 | double A_circle = area::circle(radius); 14 | std::cout << "A circle of radius " << radius << " has an area of " << A_circle 15 | << std::endl; 16 | 17 | int nSides = 19; 18 | double side = 1.29312; 19 | double A_polygon = area::polygon(nSides, side); 20 | std::cout << "A regular polygon of " << nSides << " sides of length " << side 21 | << " has an area of " << A_polygon << std::endl; 22 | 23 | double d1 = 5.0; 24 | double d2 = 7.8912; 25 | double A_rhombus = area::rhombus(d1, d2); 26 | std::cout << "A rhombus of major diagonal " << d1 << " and minor diagonal " << d2 27 | << " has an area of " << A_rhombus << std::endl; 28 | 29 | double l = 10.0; 30 | double A_square = area::square(l); 31 | std::cout << "A square of side " << l << " has an area of " << A_square 32 | << std::endl; 33 | 34 | return EXIT_SUCCESS; 35 | } 36 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_circle.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_circle.hpp" 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | namespace geometry { 7 | namespace area { 8 | double circle(double radius) { return M_PI * std::pow(radius, 2); } 9 | } // namespace area 10 | } // namespace geometry 11 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_circle.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double circle(double area); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_polygon.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_polygon.hpp" 2 | 3 | #define _USE_MATH_DEFINES 4 | #include 5 | 6 | namespace geometry { 7 | namespace area { 8 | double polygon(int nSides, double side) { 9 | double perimeter = nSides * side; 10 | double apothem = side / (2.0 * std::tan(M_PI / nSides)); 11 | return (perimeter * apothem) / 2.0; 12 | } 13 | } // namespace area 14 | } // namespace geometry 15 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_polygon.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double polygon(int nSides, double side); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_rhombus.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_rhombus.hpp" 2 | 3 | namespace geometry { 4 | namespace area { 5 | double rhombus(double d1, double d2) { return (d1 * d2) / 2.0; } 6 | } // namespace area 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_rhombus.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double rhombus(double d1, double d2); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_square.cpp: -------------------------------------------------------------------------------- 1 | #include "geometry_square.hpp" 2 | 3 | #include 4 | 5 | namespace geometry { 6 | namespace area { 7 | double square(double l) { return std::pow(l, 2); } 8 | } // namespace area 9 | } // namespace geometry 10 | -------------------------------------------------------------------------------- /content/code/day-1/03_loops-cxx/solution/geometry_square.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace geometry { 4 | namespace area { 5 | double square(double l); 6 | } 7 | } // namespace geometry 8 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME set minimum cmake version 2 | cmake_minimum_required(...) 3 | 4 | # FIXME project name and language 5 | project(libraries ...) 6 | 7 | # FIXME expose options to the user 8 | option(...) 9 | 10 | message(STATUS "Compile sources into a library? ${USE_LIBRARY}") 11 | 12 | include(CMakeDependentOption) 13 | 14 | # FIXME second option depends on the value of the first 15 | cmake_dependent_option( 16 | MAKE_STATIC_LIBRARY ...) 17 | 18 | # FIXME third option depends on the value of the first 19 | cmake_dependent_option( 20 | MAKE_SHARED_LIBRARY ...) 21 | 22 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 23 | 24 | if(USE_LIBRARY) 25 | message(STATUS "Compile sources into a STATIC library? ${MAKE_STATIC_LIBRARY}") 26 | message(STATUS "Compile sources into a SHARED library? ${MAKE_SHARED_LIBRARY}") 27 | 28 | # FIXME create executable from hello-world.cpp 29 | add_executable(hello-world ...) 30 | 31 | if(MAKE_SHARED_LIBRARY) 32 | # FIXME create a shared library 33 | add_library(message-shared ...) 34 | 35 | # FIXME link executable to shared library 36 | target_link_libraries(hello-world ...) 37 | endif() 38 | 39 | if(MAKE_STATIC_LIBRARY) 40 | # FIXME create a static library 41 | add_library(message-static ...) 42 | 43 | # FIXME link executable to static library 44 | target_link_libraries(hello-world ...) 45 | endif() 46 | else() 47 | # FIXME create executable from all sources 48 | add_executable(hello-world ...) 49 | endif() 50 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::ostream &Message::printObject(std::ostream &os) { 7 | os << "This is my very nice message: " << std::endl; 8 | os << message_; 9 | 10 | return os; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/Message.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Message { 7 | public: 8 | Message(const std::string &m) : message_(m) {} 9 | 10 | friend std::ostream &operator<<(std::ostream &os, Message &obj) { 11 | return obj.printObject(os); 12 | } 13 | 14 | private: 15 | std::string message_; 16 | std::ostream &printObject(std::ostream &os); 17 | }; 18 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | Message say_hello("Hello, CMake World!"); 8 | 9 | std::cout << say_hello << std::endl; 10 | 11 | Message say_goodbye("Goodbye, CMake World"); 12 | 13 | std::cout << say_goodbye << std::endl; 14 | 15 | return EXIT_SUCCESS; 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(options LANGUAGES CXX) 6 | 7 | # expose options to the user 8 | option(USE_LIBRARY "Compile sources into a library" OFF) 9 | 10 | message(STATUS "Compile sources into a library? ${USE_LIBRARY}") 11 | 12 | include(CMakeDependentOption) 13 | 14 | # second option depends on the value of the first 15 | cmake_dependent_option( 16 | MAKE_STATIC_LIBRARY "Compile sources into a static library" OFF 17 | "USE_LIBRARY" ON 18 | ) 19 | 20 | # third option depends on the value of the first 21 | cmake_dependent_option( 22 | MAKE_SHARED_LIBRARY "Compile sources into a shared library" ON 23 | "USE_LIBRARY" ON 24 | ) 25 | 26 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 27 | 28 | # list sources 29 | list(APPEND _sources Message.hpp Message.cpp) 30 | 31 | if(USE_LIBRARY) 32 | message(STATUS "Compile sources into a STATIC library? ${MAKE_STATIC_LIBRARY}") 33 | message(STATUS "Compile sources into a SHARED library? ${MAKE_SHARED_LIBRARY}") 34 | 35 | add_executable(hello-world hello-world.cpp) 36 | 37 | if(MAKE_SHARED_LIBRARY) 38 | add_library(message SHARED ${_sources}) 39 | 40 | target_link_libraries(hello-world PRIVATE message) 41 | endif() 42 | 43 | if(MAKE_STATIC_LIBRARY) 44 | add_library(message STATIC ${_sources}) 45 | 46 | target_link_libraries(hello-world PRIVATE message) 47 | endif() 48 | else() 49 | add_executable(hello-world hello-world.cpp ${_sources}) 50 | endif() 51 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/solution/Message.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::ostream &Message::printObject(std::ostream &os) { 7 | os << "This is my very nice message: " << std::endl; 8 | os << message_; 9 | 10 | return os; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/solution/Message.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class Message { 7 | public: 8 | Message(const std::string &m) : message_(m) {} 9 | 10 | friend std::ostream &operator<<(std::ostream &os, Message &obj) { 11 | return obj.printObject(os); 12 | } 13 | 14 | private: 15 | std::string message_; 16 | std::ostream &printObject(std::ostream &os); 17 | }; 18 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-cxx/solution/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include "Message.hpp" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | Message say_hello("Hello, CMake World!"); 8 | 9 | std::cout << say_hello << std::endl; 10 | 11 | Message say_goodbye("Goodbye, CMake World"); 12 | 13 | std::cout << say_goodbye << std::endl; 14 | 15 | return EXIT_SUCCESS; 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-f/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME set minimum cmake version 2 | cmake_minimum_required(...) 3 | 4 | # FIXME project name and language 5 | project(libraries ...) 6 | 7 | # FIXME expose options to the user 8 | option(...) 9 | 10 | message(STATUS "Compile sources into a library? ${USE_LIBRARY}") 11 | 12 | include(CMakeDependentOption) 13 | 14 | # FIXME second option depends on the value of the first 15 | cmake_dependent_option( 16 | MAKE_STATIC_LIBRARY ...) 17 | 18 | # FIXME third option depends on the value of the first 19 | cmake_dependent_option( 20 | MAKE_SHARED_LIBRARY ...) 21 | 22 | if(USE_LIBRARY) 23 | message(STATUS "Compile sources into a STATIC library? ${MAKE_STATIC_LIBRARY}") 24 | message(STATUS "Compile sources into a SHARED library? ${MAKE_SHARED_LIBRARY}") 25 | 26 | # FIXME create executable from hello-world.f90 27 | add_executable(hello-world ...) 28 | 29 | if(MAKE_SHARED_LIBRARY) 30 | # FIXME create a shared library 31 | add_library(message-shared ...) 32 | 33 | # FIXME link executable to shared library 34 | target_link_libraries(hello-world ...) 35 | endif() 36 | 37 | if(MAKE_STATIC_LIBRARY) 38 | # FIXME create a static library 39 | add_library(message-static ...) 40 | 41 | # FIXME link executable to static library 42 | target_link_libraries(hello-world ...) 43 | endif() 44 | else() 45 | # FIXME create executable from all sources 46 | add_executable(hello-world ...) 47 | endif() 48 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-f/hello-world.f90: -------------------------------------------------------------------------------- 1 | program hello_world 2 | 3 | use messaging 4 | 5 | implicit none 6 | 7 | type(Messenger) :: hello, bye 8 | 9 | hello%message_ = 'Hello, CMake world!' 10 | print *, print_message(hello) 11 | 12 | bye%message_ = 'Bye, CMake world!' 13 | print *, print_message(bye) 14 | 15 | end program 16 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-f/message.f90: -------------------------------------------------------------------------------- 1 | module messaging 2 | 3 | implicit none 4 | 5 | public Messenger 6 | type Messenger 7 | character(len=19) :: message_ 8 | end type 9 | 10 | public print_message 11 | 12 | private 13 | 14 | contains 15 | 16 | pure function print_message(postman) result(m) 17 | 18 | type(Messenger), intent(in) :: postman 19 | character(len=19) :: m 20 | 21 | m = postman%message_ 22 | 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-f/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(libraries LANGUAGES Fortran) 6 | 7 | # expose options to the user 8 | option(USE_LIBRARY "Compile sources into a library" OFF) 9 | 10 | message(STATUS "Compile sources into a library? ${USE_LIBRARY}") 11 | 12 | include(CMakeDependentOption) 13 | 14 | # second option depends on the value of the first 15 | cmake_dependent_option( 16 | MAKE_STATIC_LIBRARY "Compile sources into a static library" OFF 17 | "USE_LIBRARY" ON 18 | ) 19 | 20 | # third option depends on the value of the first 21 | cmake_dependent_option( 22 | MAKE_SHARED_LIBRARY "Compile sources into a shared library" ON 23 | "USE_LIBRARY" ON 24 | ) 25 | 26 | if(USE_LIBRARY) 27 | message(STATUS "Compile sources into a STATIC library? ${MAKE_STATIC_LIBRARY}") 28 | message(STATUS "Compile sources into a SHARED library? ${MAKE_SHARED_LIBRARY}") 29 | 30 | add_executable(hello-world hello-world.f90) 31 | 32 | if(MAKE_SHARED_LIBRARY) 33 | add_library(message-shared SHARED message.f90) 34 | 35 | target_link_libraries(hello-world PRIVATE message-shared) 36 | endif() 37 | 38 | if(MAKE_STATIC_LIBRARY) 39 | add_library(message-static STATIC message.f90) 40 | 41 | target_link_libraries(hello-world PRIVATE message-static) 42 | endif() 43 | else() 44 | add_executable(hello-world hello-world.f90 message.f90) 45 | endif() 46 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-f/solution/hello-world.f90: -------------------------------------------------------------------------------- 1 | program hello_world 2 | 3 | use messaging 4 | 5 | implicit none 6 | 7 | type(Messenger) :: hello, bye 8 | 9 | hello%message_ = 'Hello, CMake world!' 10 | print *, print_message(hello) 11 | 12 | bye%message_ = 'Bye, CMake world!' 13 | print *, print_message(bye) 14 | 15 | end program 16 | -------------------------------------------------------------------------------- /content/code/day-1/04_options-f/solution/message.f90: -------------------------------------------------------------------------------- 1 | module messaging 2 | 3 | implicit none 4 | 5 | public Messenger 6 | type Messenger 7 | character(len=19) :: message_ 8 | end type 9 | 10 | public print_message 11 | 12 | private 13 | 14 | contains 15 | 16 | pure function print_message(postman) result(m) 17 | 18 | type(Messenger), intent(in) :: postman 19 | character(len=19) :: m 20 | 21 | m = postman%message_ 22 | 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(hello-ctest LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # example library 13 | add_library(sum_integers sum_integers.cpp) 14 | 15 | # main code 16 | add_executable(sum_up main.cpp) 17 | target_link_libraries(sum_up PRIVATE sum_integers) 18 | 19 | # testing binary 20 | add_executable(cpp_test test.cpp) 21 | target_link_libraries(cpp_test PRIVATE sum_integers) 22 | 23 | # enable testing functionality 24 | enable_testing() 25 | 26 | # define tests 27 | add_test( 28 | NAME cpp_test 29 | COMMAND $ 30 | ) 31 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/solution/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/solution/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/solution/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/solution/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int main() { 6 | auto integers = {1, 2, 3, 4, 5}; 7 | 8 | if (sum_integers(integers) == 15) { 9 | return 0; 10 | } else { 11 | return 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-1/05_hello-ctest/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int main() { 6 | auto integers = {1, 2, 3, 4, 5}; 7 | 8 | if (sum_integers(integers) == 15) { 9 | return 0; 10 | } else { 11 | return 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(hello-ctest LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # example library 13 | add_library(sum_integers sum_integers.cpp) 14 | 15 | # main code 16 | add_executable(sum_up main.cpp) 17 | target_link_libraries(sum_up PRIVATE sum_integers) 18 | 19 | # testing binary 20 | add_executable(cpp_test test.cpp) 21 | target_link_libraries(cpp_test PRIVATE sum_integers) 22 | 23 | # enable testing functionality 24 | enable_testing() 25 | 26 | # define tests 27 | add_test( 28 | NAME cpp_test 29 | COMMAND $ 30 | ) 31 | 32 | # FIXME find the bash executable and save its location to the BASH_EXECUTABLE variable 33 | find_program(BASH_EXECUTABLE ...) 34 | 35 | # FIXME add a test running the test.sh shell script 36 | add_test( 37 | NAME bash_test 38 | COMMAND ... ... $ 39 | ) 40 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(hello-ctest LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # example library 13 | add_library(sum_integers sum_integers.cpp) 14 | 15 | # main code 16 | add_executable(sum_up main.cpp) 17 | target_link_libraries(sum_up PRIVATE sum_integers) 18 | 19 | # testing binary 20 | add_executable(cpp_test test.cpp) 21 | target_link_libraries(cpp_test PRIVATE sum_integers) 22 | 23 | # enable testing functionality 24 | enable_testing() 25 | 26 | # define tests 27 | add_test( 28 | NAME cpp_test 29 | COMMAND $ 30 | ) 31 | 32 | # run the main executable through a shell script 33 | find_program(BASH_EXECUTABLE NAMES bash REQUIRED) 34 | 35 | add_test( 36 | NAME bash_test 37 | COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.sh $ 38 | ) 39 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/solution/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/solution/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/solution/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/solution/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int main() { 6 | auto integers = {1, 2, 3, 4, 5}; 7 | 8 | if (sum_integers(integers) == 15) { 9 | return 0; 10 | } else { 11 | return 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/solution/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | EXECUTABLE=$1 4 | 5 | OUTPUT=$($EXECUTABLE 1 2 3 4) 6 | 7 | if [ "$OUTPUT" = "10" ] 8 | then 9 | exit 0 10 | else 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int main() { 6 | auto integers = {1, 2, 3, 4, 5}; 7 | 8 | if (sum_integers(integers) == 15) { 9 | return 0; 10 | } else { 11 | return 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /content/code/day-1/06_bash-ctest/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | EXECUTABLE=$1 4 | 5 | OUTPUT=$($EXECUTABLE 1 2 3 4) 6 | 7 | if [ "$OUTPUT" = "10" ] 8 | then 9 | exit 0 10 | else 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(hello-ctest LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # example library 13 | add_library(sum_integers sum_integers.cpp) 14 | 15 | # main code 16 | add_executable(sum_up main.cpp) 17 | target_link_libraries(sum_up PRIVATE sum_integers) 18 | 19 | # testing binary 20 | add_executable(cpp_test test.cpp) 21 | target_link_libraries(cpp_test PRIVATE sum_integers) 22 | 23 | # enable testing functionality 24 | enable_testing() 25 | 26 | # define tests 27 | add_test( 28 | NAME cpp_test 29 | COMMAND $ 30 | ) 31 | 32 | # run the main executable through a shell script 33 | find_program(BASH_EXECUTABLE NAMES bash REQUIRED) 34 | 35 | add_test( 36 | NAME bash_test 37 | COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.sh $ 38 | ) 39 | 40 | # FIXME find the Python interpreter 41 | find_package(...) 42 | 43 | # FIXME add a test run through test.py 44 | add_test( 45 | NAME python_test_long 46 | COMMAND ... ... --executable $ 47 | ) 48 | 49 | # FIXME add another test run through test.py, with options 50 | add_test( 51 | NAME python_test_short 52 | COMMAND ... ... --executable $ 53 | ) 54 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(hello-ctest LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # example library 13 | add_library(sum_integers sum_integers.cpp) 14 | 15 | # main code 16 | add_executable(sum_up main.cpp) 17 | target_link_libraries(sum_up PRIVATE sum_integers) 18 | 19 | # testing binary 20 | add_executable(cpp_test test.cpp) 21 | target_link_libraries(cpp_test PRIVATE sum_integers) 22 | 23 | # enable testing functionality 24 | enable_testing() 25 | 26 | # define tests 27 | add_test( 28 | NAME cpp_test 29 | COMMAND $ 30 | ) 31 | 32 | # run the main executable through a shell script 33 | find_program(BASH_EXECUTABLE NAMES bash REQUIRED) 34 | 35 | add_test( 36 | NAME bash_test 37 | COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.sh $ 38 | ) 39 | 40 | # run the main executable through a Python script 41 | find_package(Python REQUIRED) 42 | 43 | add_test( 44 | NAME python_test_long 45 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py --executable $ 46 | ) 47 | 48 | add_test( 49 | NAME python_test_short 50 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py --short --executable $ 51 | ) 52 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/solution/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/solution/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/solution/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/solution/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int main() { 6 | auto integers = {1, 2, 3, 4, 5}; 7 | 8 | if (sum_integers(integers) == 15) { 9 | return 0; 10 | } else { 11 | return 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/solution/test.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import argparse 3 | 4 | # test script expects the executable as argument 5 | parser = argparse.ArgumentParser() 6 | parser.add_argument('--executable', 7 | help='full path to executable') 8 | parser.add_argument('--short', 9 | default=False, 10 | action='store_true', 11 | help='run a shorter test') 12 | args = parser.parse_args() 13 | 14 | 15 | def execute_cpp_code(integers): 16 | result = subprocess.check_output([args.executable] + integers) 17 | return int(result) 18 | 19 | 20 | if args.short: 21 | # we collect [1, 2, ..., 100] as a list of strings 22 | result = execute_cpp_code([str(i) for i in range(1, 101)]) 23 | assert result == 5050, 'summing up to 100 failed' 24 | else: 25 | # we collect [1, 2, ..., 1000] as a list of strings 26 | result = execute_cpp_code([str(i) for i in range(1, 1001)]) 27 | assert result == 500500, 'summing up to 1000 failed' 28 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/solution/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | EXECUTABLE=$1 4 | 5 | OUTPUT=$($EXECUTABLE 1 2 3 4) 6 | 7 | if [ "$OUTPUT" = "10" ] 8 | then 9 | exit 0 10 | else 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int main() { 6 | auto integers = {1, 2, 3, 4, 5}; 7 | 8 | if (sum_integers(integers) == 15) { 9 | return 0; 10 | } else { 11 | return 1; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/test.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import argparse 3 | 4 | # test script expects the executable as argument 5 | parser = argparse.ArgumentParser() 6 | parser.add_argument('--executable', 7 | help='full path to executable') 8 | parser.add_argument('--short', 9 | default=False, 10 | action='store_true', 11 | help='run a shorter test') 12 | args = parser.parse_args() 13 | 14 | 15 | def execute_cpp_code(integers): 16 | result = subprocess.check_output([args.executable] + integers) 17 | return int(result) 18 | 19 | 20 | if args.short: 21 | # we collect [1, 2, ..., 100] as a list of strings 22 | result = execute_cpp_code([str(i) for i in range(1, 101)]) 23 | assert result == 5050, 'summing up to 100 failed' 24 | else: 25 | # we collect [1, 2, ..., 1000] as a list of strings 26 | result = execute_cpp_code([str(i) for i in range(1, 1001)]) 27 | assert result == 500500, 'summing up to 1000 failed' 28 | -------------------------------------------------------------------------------- /content/code/day-1/07_python-ctest/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | EXECUTABLE=$1 4 | 5 | OUTPUT=$($EXECUTABLE 1 2 3 4) 6 | 7 | if [ "$OUTPUT" = "10" ] 8 | then 9 | exit 0 10 | else 11 | exit 1 12 | fi 13 | -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name 5 | project(ctest-labels LANGUAGES NONE) 6 | 7 | # FIXME detect python 8 | find_package(...) 9 | 10 | # FIXME enable testing 11 | 12 | # FIXME add tests 13 | add_test(...) 14 | 15 | # FIXME set the "quick" label 16 | set_tests_properties(...) 17 | 18 | # FIXME set the "long" label 19 | set_tests_properties(...) 20 | -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name 5 | project(ctest-labels LANGUAGES NONE) 6 | 7 | # detect python 8 | find_package(Python REQUIRED) 9 | 10 | # define tests 11 | enable_testing() 12 | 13 | add_test( 14 | NAME feature-a 15 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/feature-a.py 16 | ) 17 | 18 | add_test( 19 | NAME feature-b 20 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/feature-b.py 21 | ) 22 | 23 | add_test( 24 | NAME feature-c 25 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/feature-c.py 26 | ) 27 | 28 | add_test( 29 | NAME feature-d 30 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/feature-d.py 31 | ) 32 | 33 | add_test( 34 | NAME benchmark-a 35 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/benchmark-a.py 36 | ) 37 | 38 | add_test( 39 | NAME benchmark-b 40 | COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/benchmark-b.py 41 | ) 42 | 43 | set_tests_properties( 44 | feature-a 45 | feature-b 46 | feature-c 47 | PROPERTIES 48 | LABELS "quick" 49 | ) 50 | 51 | set_tests_properties( 52 | feature-d 53 | benchmark-a 54 | benchmark-b 55 | PROPERTIES 56 | LABELS "long" 57 | ) 58 | -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/solution/test/benchmark-a.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 0.5 seconds 5 | time.sleep(0.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/solution/test/benchmark-b.py: -------------------------------------------------------------------------------- 1 | benchmark-a.py -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/solution/test/feature-a.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 0.1 seconds 5 | time.sleep(0.1) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/solution/test/feature-b.py: -------------------------------------------------------------------------------- 1 | feature-a.py -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/solution/test/feature-c.py: -------------------------------------------------------------------------------- 1 | feature-a.py -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/solution/test/feature-d.py: -------------------------------------------------------------------------------- 1 | benchmark-a.py -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/test/benchmark-a.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 0.5 seconds 5 | time.sleep(0.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/test/benchmark-b.py: -------------------------------------------------------------------------------- 1 | benchmark-a.py -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/test/feature-a.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 0.1 seconds 5 | time.sleep(0.1) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/test/feature-b.py: -------------------------------------------------------------------------------- 1 | feature-a.py -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/test/feature-c.py: -------------------------------------------------------------------------------- 1 | feature-a.py -------------------------------------------------------------------------------- /content/code/day-1/08_ctest-labels/test/feature-d.py: -------------------------------------------------------------------------------- 1 | benchmark-a.py -------------------------------------------------------------------------------- /content/code/day-1/09_ctest-will-fail/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name 5 | project(ctest-will-faile LANGUAGES NONE) 6 | 7 | # detect python 8 | find_package(Python REQUIRED) 9 | 10 | # define tests 11 | enable_testing() 12 | 13 | add_test(example ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py) 14 | 15 | # we expect this test to fail 16 | set_tests_properties(example PROPERTIES WILL_FAIL true) 17 | -------------------------------------------------------------------------------- /content/code/day-1/09_ctest-will-fail/solution/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # simulate a failing test 4 | sys.exit(1) 5 | -------------------------------------------------------------------------------- /content/code/day-1/09_ctest-will-fail/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # simulate a failing test 4 | sys.exit(1) 5 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name 5 | project(ctest-cost LANGUAGES NONE) 6 | 7 | # detect python 8 | find_package(Python REQUIRED) 9 | 10 | # FIXME enable testing 11 | 12 | # FIXME add tests 13 | add_test(...) 14 | 15 | # FIXME set tests properties 16 | set_tests_properties(...) 17 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name 5 | project(ctest-cost LANGUAGES NONE) 6 | 7 | # detect python 8 | find_package(Python REQUIRED) 9 | 10 | # define tests 11 | enable_testing() 12 | 13 | add_test(a ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/a.py) 14 | add_test(b ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/b.py) 15 | add_test(c ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/c.py) 16 | add_test(d ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/d.py) 17 | set_tests_properties(a b c d PROPERTIES COST 0.5) 18 | 19 | add_test(e ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/e.py) 20 | add_test(f ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/f.py) 21 | add_test(g ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/g.py) 22 | set_tests_properties(e f g PROPERTIES COST 1.5) 23 | 24 | add_test(h ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/h.py) 25 | set_tests_properties(h PROPERTIES COST 2.5) 26 | 27 | add_test(i ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/i.py) 28 | set_tests_properties(i PROPERTIES COST 3.5) 29 | 30 | add_test(j ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/j.py) 31 | set_tests_properties(j PROPERTIES COST 4.5) 32 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/a.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 0.5 seconds 5 | time.sleep(0.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/b.py: -------------------------------------------------------------------------------- 1 | a.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/c.py: -------------------------------------------------------------------------------- 1 | a.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/d.py: -------------------------------------------------------------------------------- 1 | a.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/e.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 1.5 seconds 5 | time.sleep(1.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/f.py: -------------------------------------------------------------------------------- 1 | e.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/g.py: -------------------------------------------------------------------------------- 1 | e.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/h.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 2.5 seconds 5 | time.sleep(2.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/i.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 3.5 seconds 5 | time.sleep(3.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/solution/test/j.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 4.5 seconds 5 | time.sleep(4.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/a.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 0.5 seconds 5 | time.sleep(0.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/b.py: -------------------------------------------------------------------------------- 1 | a.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/c.py: -------------------------------------------------------------------------------- 1 | a.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/d.py: -------------------------------------------------------------------------------- 1 | a.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/e.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 1.5 seconds 5 | time.sleep(1.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/f.py: -------------------------------------------------------------------------------- 1 | e.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/g.py: -------------------------------------------------------------------------------- 1 | e.py -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/h.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 2.5 seconds 5 | time.sleep(2.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/i.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 3.5 seconds 5 | time.sleep(3.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/10_ctest-cost/test/j.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 4.5 seconds 5 | time.sleep(4.5) 6 | 7 | # finally report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/11_ctest-timeout/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name 5 | project(ctest-timeout LANGUAGES NONE) 6 | 7 | # detect python 8 | find_package(Python REQUIRED) 9 | 10 | # define tests 11 | enable_testing() 12 | 13 | # we expect this test to run for 2 seconds 14 | add_test(example ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py) 15 | 16 | # timeout for this test set to 10 seconds 17 | set_tests_properties(example PROPERTIES TIMEOUT 10) 18 | -------------------------------------------------------------------------------- /content/code/day-1/11_ctest-timeout/solution/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 2 seconds 5 | time.sleep(2) 6 | 7 | # report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/11_ctest-timeout/test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | # wait for 2 seconds 5 | time.sleep(2) 6 | 7 | # report success 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /content/code/day-1/12_OS/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name, in this case no language required 5 | project(OS LANGUAGES NONE) 6 | 7 | # print custom message depending on the operating system 8 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 9 | message(STATUS "Configuring on/for Linux") 10 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 11 | message(STATUS "Configuring on/for macOS") 12 | elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") 13 | message(STATUS "Configuring on/for Windows") 14 | elseif(CMAKE_SYSTEM_NAME STREQUAL "AIX") 15 | message(STATUS "Configuring on/for IBM AIX") 16 | else() 17 | message(STATUS "Configuring on/for ${CMAKE_SYSTEM_NAME}") 18 | endif() 19 | -------------------------------------------------------------------------------- /content/code/day-1/13_processor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(processor LANGUAGES NONE) 6 | 7 | # the value of NUMBER_OF_LOGICAL_CORES will be saved in _NUMBER_OF_LOGICAL_CORES 8 | cmake_host_system_information(...) 9 | message(...) 10 | -------------------------------------------------------------------------------- /content/code/day-1/13_processor/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(processor LANGUAGES NONE) 6 | 7 | # the value of NUMBER_OF_LOGICAL_CORES will be saved in _NUMBER_OF_LOGICAL_CORES 8 | cmake_host_system_information(RESULT _NUMBER_OF_LOGICAL_CORES QUERY NUMBER_OF_LOGICAL_CORES) 9 | message(STATUS "Number of logical cores : ${_NUMBER_OF_LOGICAL_CORES}") 10 | -------------------------------------------------------------------------------- /content/code/day-1/14_host_system_information/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(processor LANGUAGES NONE) 6 | 7 | include(CMakePrintHelpers) 8 | 9 | foreach(key 10 | IN ITEMS 11 | ...) 12 | ) 13 | # query the item ${key} and save its value in the variable _${key} 14 | # i.e. the value of NUMBER_OF_LOGICAL_CORES will be saved in _NUMBER_OF_LOGICAL_CORES 15 | cmake_host_system_information(...) 16 | cmake_print_variables(...) 17 | endforeach() 18 | -------------------------------------------------------------------------------- /content/code/day-1/14_host_system_information/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(processor LANGUAGES NONE) 6 | 7 | include(CMakePrintHelpers) 8 | 9 | foreach(key 10 | IN ITEMS 11 | NUMBER_OF_LOGICAL_CORES 12 | NUMBER_OF_PHYSICAL_CORES 13 | TOTAL_VIRTUAL_MEMORY 14 | AVAILABLE_VIRTUAL_MEMORY 15 | TOTAL_PHYSICAL_MEMORY 16 | AVAILABLE_PHYSICAL_MEMORY 17 | IS_64BIT 18 | HAS_FPU 19 | HAS_MMX 20 | HAS_MMX_PLUS 21 | HAS_SSE 22 | HAS_SSE2 23 | HAS_SSE_FP 24 | HAS_SSE_MMX 25 | HAS_AMD_3DNOW 26 | HAS_AMD_3DNOW_PLUS 27 | HAS_IA64 28 | OS_NAME 29 | OS_RELEASE 30 | OS_VERSION 31 | OS_PLATFORM 32 | ) 33 | # query the item ${key} and save its value in the variable _${key} 34 | # i.e. the value of NUMBER_OF_LOGICAL_CORES will be saved in _NUMBER_OF_LOGICAL_CORES 35 | cmake_host_system_information(RESULT _${key} QUERY ${key}) 36 | cmake_print_variables(_${key}) 37 | endforeach() 38 | -------------------------------------------------------------------------------- /content/code/day-1/15_sys_preproc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(sys_preproc LANGUAGES CXX) 6 | 7 | # define executable and its source file 8 | add_executable(hello-world hello-world.cpp) 9 | 10 | # let the preprocessor know about the system name 11 | if(CMAKE_SYSTEM_NAME ...) 12 | # add IS_LINUX definition 13 | target_compile_definitions(...) 14 | endif() 15 | if(CMAKE_SYSTEM_NAME ...) 16 | # add IS_MACOS definition 17 | target_compile_definitions(...) 18 | endif() 19 | if(CMAKE_SYSTEM_NAME ...) 20 | # add IS_WINDOWS definition 21 | target_compile_definitions(...) 22 | endif() 23 | -------------------------------------------------------------------------------- /content/code/day-1/15_sys_preproc/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::string say_hello() { 6 | #ifdef IS_WINDOWS 7 | return std::string("Hello from Windows!"); 8 | #elif IS_LINUX 9 | return std::string("Hello from Linux!"); 10 | #elif IS_MACOS 11 | return std::string("Hello from macOS!"); 12 | #else 13 | return std::string("Hello from an unknown system!"); 14 | #endif 15 | } 16 | 17 | int main() { 18 | std::cout << say_hello() << std::endl; 19 | return EXIT_SUCCESS; 20 | } 21 | -------------------------------------------------------------------------------- /content/code/day-1/15_sys_preproc/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(sys_preproc LANGUAGES CXX) 6 | 7 | # define executable and its source file 8 | add_executable(hello-world hello-world.cpp) 9 | 10 | # let the preprocessor know about the system name 11 | if(CMAKE_SYSTEM_NAME STREQUAL "Linux") 12 | target_compile_definitions(hello-world PUBLIC "IS_LINUX") 13 | endif() 14 | if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") 15 | target_compile_definitions(hello-world PUBLIC "IS_MACOS") 16 | endif() 17 | if(CMAKE_SYSTEM_NAME STREQUAL "Windows") 18 | target_compile_definitions(hello-world PUBLIC "IS_WINDOWS") 19 | endif() 20 | -------------------------------------------------------------------------------- /content/code/day-1/15_sys_preproc/solution/hello-world.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | std::string say_hello() { 6 | #ifdef IS_WINDOWS 7 | return std::string("Hello from Windows!"); 8 | #elif IS_LINUX 9 | return std::string("Hello from Linux!"); 10 | #elif IS_MACOS 11 | return std::string("Hello from macOS!"); 12 | #else 13 | return std::string("Hello from an unknown system!"); 14 | #endif 15 | } 16 | 17 | int main() { 18 | std::cout << say_hello() << std::endl; 19 | return EXIT_SUCCESS; 20 | } 21 | -------------------------------------------------------------------------------- /content/code/day-1/16_configure/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(processor LANGUAGES CXX) 6 | 7 | add_executable(processor-info processor-info.cpp) 8 | 9 | include(CMakePrintHelpers) 10 | 11 | foreach(key 12 | IN ITEMS 13 | ... 14 | ) 15 | # query the item ${key} and save its value in the variable _${key} 16 | # i.e. the value of NUMBER_OF_LOGICAL_CORES will be saved in _NUMBER_OF_LOGICAL_CORES 17 | cmake_host_system_information(RESULT ... QUERY ...) 18 | cmake_print_variables(...) 19 | endforeach() 20 | 21 | # and PPROJECT_BINARY_DIR as its include directories 22 | target_include_directories(processor-info 23 | ... 24 | ) 25 | 26 | # configure the file 27 | configure_file(... ... @ONLY) 28 | -------------------------------------------------------------------------------- /content/code/day-1/16_configure/config.h.in: -------------------------------------------------------------------------------- 1 | solution/config.h.in -------------------------------------------------------------------------------- /content/code/day-1/16_configure/processor-info.cpp: -------------------------------------------------------------------------------- 1 | solution/processor-info.cpp -------------------------------------------------------------------------------- /content/code/day-1/16_configure/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(processor LANGUAGES CXX) 6 | 7 | add_executable(processor-info processor-info.cpp) 8 | 9 | include(CMakePrintHelpers) 10 | 11 | foreach(key 12 | IN ITEMS 13 | NUMBER_OF_PHYSICAL_CORES 14 | TOTAL_PHYSICAL_MEMORY 15 | OS_NAME 16 | OS_PLATFORM 17 | ) 18 | # query the item ${key} and save its value in the variable _${key} 19 | # i.e. the value of NUMBER_OF_LOGICAL_CORES will be saved in _NUMBER_OF_LOGICAL_CORES 20 | cmake_host_system_information(RESULT _${key} QUERY ${key}) 21 | cmake_print_variables(_${key}) 22 | endforeach() 23 | 24 | # and its include directories 25 | target_include_directories(processor-info 26 | PRIVATE 27 | ${PROJECT_BINARY_DIR} 28 | ) 29 | 30 | # configure the file 31 | configure_file(config.h.in config.h @ONLY) 32 | -------------------------------------------------------------------------------- /content/code/day-1/16_configure/solution/config.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NUMBER_OF_PHYSICAL_CORES @_NUMBER_OF_PHYSICAL_CORES@ 4 | #define TOTAL_PHYSICAL_MEMORY @_TOTAL_PHYSICAL_MEMORY@ 5 | #define OS_NAME "@_OS_NAME@" 6 | #define OS_PLATFORM "@_OS_PLATFORM@" 7 | -------------------------------------------------------------------------------- /content/code/day-1/16_configure/solution/processor-info.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "config.h" 5 | 6 | int main() { 7 | std::cout << "Number of physical cores: " << NUMBER_OF_PHYSICAL_CORES 8 | << std::endl; 9 | 10 | std::cout << "Total physical memory in megabytes: " << TOTAL_PHYSICAL_MEMORY 11 | << std::endl; 12 | 13 | std::cout << "OS name: " << OS_NAME << std::endl; 14 | std::cout << "OS platform: " << OS_PLATFORM << std::endl; 15 | 16 | return EXIT_SUCCESS; 17 | } 18 | -------------------------------------------------------------------------------- /content/code/day-1/17_find_cffi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(find_cffi LANGUAGES NONE) 4 | 5 | find_package(Python REQUIRED) 6 | 7 | execute_process( 8 | COMMAND 9 | # FIXME provide the Python command 10 | OUTPUT_VARIABLE 11 | # FIXME provide a variable for capturing the standard output stream 12 | ERROR_VARIABLE 13 | # FIXME provide a variable for capturing the standard error stream 14 | OUTPUT_STRIP_TRAILING_WHITESPACE 15 | ERROR_STRIP_TRAILING_WHITESPACE 16 | ) 17 | 18 | # FIXME print out the contents of the standard output and standard error streams 19 | # FIXME quit if "ModuleNotFoundError" is in the standard error stream 20 | # HINT: use the MATCHES operator to search in the string 21 | -------------------------------------------------------------------------------- /content/code/day-1/17_find_cffi/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(find_cffi LANGUAGES NONE) 4 | 5 | find_package(Python REQUIRED) 6 | 7 | # this is set as variable to prepare 8 | # for abstraction using loops or functions 9 | set(_module_name "cffi") 10 | 11 | execute_process( 12 | COMMAND 13 | ${Python_EXECUTABLE} "-c" "import ${_module_name}; print(${_module_name}.__version__)" 14 | OUTPUT_VARIABLE _stdout 15 | ERROR_VARIABLE _stderr 16 | OUTPUT_STRIP_TRAILING_WHITESPACE 17 | ERROR_STRIP_TRAILING_WHITESPACE 18 | ) 19 | 20 | if(_stderr MATCHES "ModuleNotFoundError") 21 | message(STATUS "Module ${_module_name} not found") 22 | else() 23 | message(STATUS "Found module ${_module_name} v${_stdout}") 24 | endif() 25 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(pre_post LANGUAGES Fortran) 4 | 5 | find_package(Python REQUIRED) 6 | 7 | # we default to Release build type 8 | if(NOT CMAKE_BUILD_TYPE) 9 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) 10 | endif() 11 | 12 | add_executable(example) 13 | 14 | target_sources(example 15 | PRIVATE 16 | example.f90 17 | ) 18 | 19 | add_custom_command( 20 | TARGET 21 | # FIXME add the target name 22 | PRE_LINK 23 | COMMAND 24 | # FIXME call echo-file.py through Python to read the file CMakeFiles/example.dir/link.txt 25 | ${Python_EXECUTABLE} 26 | ... 27 | COMMENT 28 | "link line:" 29 | VERBATIM 30 | ) 31 | 32 | add_custom_command( 33 | TARGET 34 | # FIXME add the target name 35 | POST_BUILD 36 | COMMAND 37 | # FIXME call static-size.py through Python on the produced executable 38 | ${Python_EXECUTABLE} 39 | ... 40 | COMMENT 41 | "static size of executable:" 42 | VERBATIM 43 | ) 44 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/echo-file.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # for simplicity we do not verify the number and 4 | # type of arguments 5 | file_path = sys.argv[-1] 6 | 7 | try: 8 | with open(file_path, 'r') as f: 9 | print(f.read()) 10 | except FileNotFoundError: 11 | print(f'ERROR: file {file_path} not found') 12 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/example.f90: -------------------------------------------------------------------------------- 1 | program example 2 | 3 | implicit none 4 | 5 | real(8) :: array(20000000) 6 | real(8) :: r 7 | integer :: i 8 | 9 | do i = 1, size(array) 10 | call random_number(r) 11 | array(i) = r 12 | end do 13 | 14 | print *, sum(array) 15 | 16 | end program 17 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(pre_post LANGUAGES Fortran) 4 | 5 | find_package(Python REQUIRED) 6 | 7 | # we default to Release build type 8 | if(NOT CMAKE_BUILD_TYPE) 9 | set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) 10 | endif() 11 | 12 | add_executable(example) 13 | 14 | target_sources(example 15 | PRIVATE 16 | example.f90 17 | ) 18 | 19 | add_custom_command( 20 | TARGET 21 | example 22 | PRE_LINK 23 | COMMAND 24 | ${Python_EXECUTABLE} 25 | ${CMAKE_CURRENT_SOURCE_DIR}/echo-file.py 26 | ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/example.dir/link.txt 27 | COMMENT 28 | "link line:" 29 | VERBATIM 30 | ) 31 | 32 | add_custom_command( 33 | TARGET 34 | example 35 | POST_BUILD 36 | COMMAND 37 | ${Python_EXECUTABLE} 38 | ${CMAKE_CURRENT_SOURCE_DIR}/static-size.py 39 | $ 40 | COMMENT 41 | "static size of executable:" 42 | VERBATIM 43 | ) 44 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/solution/echo-file.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | # for simplicity we do not verify the number and 4 | # type of arguments 5 | file_path = sys.argv[-1] 6 | 7 | try: 8 | with open(file_path, 'r') as f: 9 | print(f.read()) 10 | except FileNotFoundError: 11 | print(f'ERROR: file {file_path} not found') 12 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/solution/example.f90: -------------------------------------------------------------------------------- 1 | program example 2 | 3 | implicit none 4 | 5 | real(8) :: array(20000000) 6 | real(8) :: r 7 | integer :: i 8 | 9 | do i = 1, size(array) 10 | call random_number(r) 11 | array(i) = r 12 | end do 13 | 14 | print *, sum(array) 15 | 16 | end program 17 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/solution/static-size.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | 4 | # for simplicity we do not check number of 5 | # arguments and whether the file really exists 6 | file_path = sys.argv[-1] 7 | 8 | try: 9 | output = subprocess.check_output(['size', file_path]).decode('utf-8') 10 | except FileNotFoundError: 11 | print('command "size" is not available on this platform') 12 | sys.exit(0) 13 | 14 | size = 0.0 15 | for line in output.split('\n'): 16 | if file_path in line: 17 | # we are interested in the 4th number on this line 18 | size = int(line.split()[3]) 19 | 20 | print(f'{size/1.0e6:.3f} MB') 21 | -------------------------------------------------------------------------------- /content/code/day-1/18_pre_post-f/static-size.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import sys 3 | 4 | # for simplicity we do not check number of 5 | # arguments and whether the file really exists 6 | file_path = sys.argv[-1] 7 | 8 | try: 9 | output = subprocess.check_output(['size', file_path]).decode('utf-8') 10 | except FileNotFoundError: 11 | print('command "size" is not available on this platform') 12 | sys.exit(0) 13 | 14 | size = 0.0 15 | for line in output.split('\n'): 16 | if file_path in line: 17 | # we are interested in the 4th number on this line 18 | size = int(line.split()[3]) 19 | 20 | print(f'{size/1.0e6:.3f} MB') 21 | -------------------------------------------------------------------------------- /content/code/day-1/19_check_compiler_flag/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(check_compiler_flag LANGUAGES CXX) 4 | 5 | # we set the C++ standard 6 | set(CMAKE_CXX_STANDARD 14) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | 10 | # add an executable target 11 | add_executable(asan-example asan-example.cpp) 12 | 13 | # we set some generic compiler flags 14 | target_compile_options(asan-example 15 | PUBLIC 16 | "-g3" 17 | "-O1" 18 | ) 19 | 20 | # FIXME include the correct CMake module to check that C++ compiler flags work 21 | include(...) 22 | 23 | # FIXME declare the flags to check in a new variable 24 | set(ASAN_FLAGS ...) 25 | # FIXME invoke check_cxx_compiler_flag 26 | # HINT: the flags to check need to set as a CMAKE_REQUIRED_FLAGS variable 27 | 28 | if(asan_works) 29 | # we transform ASAN_FLAGS to ;-separated list 30 | string(REPLACE " " ";" _asan_flags ${ASAN_FLAGS}) 31 | # FIXME add the _asan_flags to the compile options of the executable target 32 | target_compile_options(asan-example 33 | ... 34 | ) 35 | # this is needed for the linker to properly handle the sanitizer 36 | target_link_libraries(asan-example 37 | PUBLIC 38 | ${_asan_flags} 39 | ) 40 | endif() 41 | -------------------------------------------------------------------------------- /content/code/day-1/19_check_compiler_flag/asan-example.cpp: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int stack_array[100]; 3 | stack_array[1] = 0; 4 | return stack_array[argc + 100]; // BOOM 5 | } 6 | -------------------------------------------------------------------------------- /content/code/day-1/19_check_compiler_flag/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(check_compiler_flag LANGUAGES CXX) 4 | 5 | # we set the C++ standard 6 | set(CMAKE_CXX_STANDARD 14) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | 10 | # add an executable target 11 | add_executable(asan-example asan-example.cpp) 12 | 13 | # we set some generic compiler flags 14 | target_compile_options(asan-example 15 | PUBLIC 16 | "-g3" 17 | "-O1" 18 | ) 19 | 20 | include(CheckCXXCompilerFlag) 21 | 22 | set(ASAN_FLAGS "-fsanitize=address -fno-omit-frame-pointer") 23 | 24 | set(CMAKE_REQUIRED_FLAGS ${ASAN_FLAGS}) 25 | check_cxx_compiler_flag(${ASAN_FLAGS} asan_works) 26 | unset(CMAKE_REQUIRED_FLAGS) 27 | 28 | if(asan_works) 29 | # we transform ASAN_FLAGS to ;-separated list 30 | string(REPLACE " " ";" _asan_flags ${ASAN_FLAGS}) 31 | target_compile_options(asan-example 32 | PUBLIC 33 | ${_asan_flags} 34 | ) 35 | # this is needed for the linker to properly handle the sanitizer 36 | target_link_libraries(asan-example 37 | PUBLIC 38 | ${_asan_flags} 39 | ) 40 | endif() 41 | -------------------------------------------------------------------------------- /content/code/day-1/19_check_compiler_flag/solution/asan-example.cpp: -------------------------------------------------------------------------------- 1 | int main(int argc, char **argv) { 2 | int stack_array[100]; 3 | stack_array[1] = 0; 4 | return stack_array[argc + 100]; // BOOM 5 | } 6 | -------------------------------------------------------------------------------- /content/code/day-1/20_check_source_runs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | # the project uses both C++ and C 4 | project(check_source_runs LANGUAGES CXX C) 5 | 6 | # we set the C++ standard 7 | set(CMAKE_CXX_STANDARD 14) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | # we find the UUID system library using the pkg-config utility 12 | find_package(PkgConfig REQUIRED QUIET) 13 | pkg_search_module(UUID REQUIRED uuid IMPORTED_TARGET) 14 | if(TARGET PkgConfig::UUID) 15 | message(STATUS "Found libuuid") 16 | endif() 17 | 18 | # FIXME create the C++ executable from the use-uuid.cpp source file 19 | add_executable(...) 20 | 21 | # FIXME include the CMake module that checks whether a C source file runs 22 | include(...) 23 | 24 | # FIXME set the C code to test in a variable 25 | set(...) 26 | 27 | # FIXME perform the check 28 | # HINT: libraries required to link are to be given in a variable called CMAKE_REQUIRED_LIBRARIES 29 | 30 | # FIXME emit a fatal error if the check fails 31 | if(NOT _runs) 32 | endif() 33 | 34 | # we finally link the library to the C++ executable 35 | target_link_libraries(use-uuid 36 | PUBLIC 37 | PkgConfig::UUID 38 | ) 39 | -------------------------------------------------------------------------------- /content/code/day-1/20_check_source_runs/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | # the project uses both C++ and C 4 | project(check_source_runs LANGUAGES CXX C) 5 | 6 | # we set the C++ standard 7 | set(CMAKE_CXX_STANDARD 14) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | # we find the UUID system library using the pkg-config utility 12 | find_package(PkgConfig REQUIRED QUIET) 13 | pkg_search_module(UUID REQUIRED uuid IMPORTED_TARGET) 14 | if(TARGET PkgConfig::UUID) 15 | message(STATUS "Found libuuid") 16 | endif() 17 | 18 | # create a C++ executable using UUID 19 | add_executable(use-uuid use-uuid.cpp) 20 | 21 | # now check that we can use UUID properly 22 | include(CheckCSourceRuns) 23 | 24 | # set the C code to test in a variable 25 | set(_test_uuid 26 | " 27 | #include 28 | 29 | int main(int argc, char * argv[]) { 30 | uuid_t uuid; 31 | 32 | uuid_generate(uuid); 33 | 34 | return 0; 35 | } 36 | ") 37 | 38 | set(CMAKE_REQUIRED_LIBRARIES PkgConfig::UUID) 39 | check_c_source_runs("${_test_uuid}" _runs) 40 | unset(CMAKE_REQUIRED_LIBRARIES) 41 | 42 | if(NOT _runs) 43 | message(FATAL_ERROR "Cannot run a simple C executable using libuuid!") 44 | endif() 45 | 46 | # we finally link the library to the C++ executable 47 | target_link_libraries(use-uuid 48 | PUBLIC 49 | PkgConfig::UUID 50 | ) 51 | -------------------------------------------------------------------------------- /content/code/day-1/20_check_source_runs/solution/use-uuid.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libuuid sample program 3 | * 4 | * C version available here: 5 | * https://gist.github.com/yoggy/4483031 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | int main() { 16 | // typedef unsigned char uuid_t[16]; 17 | uuid_t uuid; 18 | 19 | // generate 20 | uuid_generate(uuid); 21 | 22 | // unparse (to string) 23 | char uuid_str[37]; // ex. "1b4e28ba-2fa1-11d2-883f-0016d3cca427" + "\0" 24 | uuid_unparse_lower(uuid, uuid_str); 25 | std::cout << "Generate UUID = " << uuid_str << std::endl; 26 | 27 | // parse (from string) 28 | uuid_t uuid2; 29 | uuid_parse(uuid_str, uuid2); 30 | 31 | // compare (retval == 0) 32 | int retval; 33 | retval = uuid_compare(uuid, uuid2); 34 | std::cout << "uuid_compare() result = " << retval << std::endl; 35 | 36 | // compare (retval == 1) 37 | uuid_t uuid3; 38 | uuid_parse("1b4e28ba-2fa1-11d2-883f-0016d3cca427", uuid3); 39 | retval = uuid_compare(uuid, uuid3); 40 | std::cout << "uuid_compare() result = " << retval << std::endl; 41 | 42 | // is null? (retval == 0) 43 | retval = uuid_is_null(uuid); 44 | std::cout << "uuid_null() result = " << retval << std::endl; 45 | 46 | // is null? (retval == 1) 47 | uuid_clear(uuid); 48 | retval = uuid_is_null(uuid); 49 | std::cout << "uuid_null() result = " << retval << std::endl; 50 | 51 | return EXIT_SUCCESS; 52 | } 53 | -------------------------------------------------------------------------------- /content/code/day-1/20_check_source_runs/use-uuid.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * libuuid sample program 3 | * 4 | * C version available here: 5 | * https://gist.github.com/yoggy/4483031 6 | * 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | int main() { 16 | // typedef unsigned char uuid_t[16]; 17 | uuid_t uuid; 18 | 19 | // generate 20 | uuid_generate(uuid); 21 | 22 | // unparse (to string) 23 | char uuid_str[37]; // ex. "1b4e28ba-2fa1-11d2-883f-0016d3cca427" + "\0" 24 | uuid_unparse_lower(uuid, uuid_str); 25 | std::cout << "Generate UUID = " << uuid_str << std::endl; 26 | 27 | // parse (from string) 28 | uuid_t uuid2; 29 | uuid_parse(uuid_str, uuid2); 30 | 31 | // compare (retval == 0) 32 | int retval; 33 | retval = uuid_compare(uuid, uuid2); 34 | std::cout << "uuid_compare() result = " << retval << std::endl; 35 | 36 | // compare (retval == 1) 37 | uuid_t uuid3; 38 | uuid_parse("1b4e28ba-2fa1-11d2-883f-0016d3cca427", uuid3); 39 | retval = uuid_compare(uuid, uuid3); 40 | std::cout << "uuid_compare() result = " << retval << std::endl; 41 | 42 | // is null? (retval == 0) 43 | retval = uuid_is_null(uuid); 44 | std::cout << "uuid_null() result = " << retval << std::endl; 45 | 46 | // is null? (retval == 1) 47 | uuid_clear(uuid); 48 | retval = uuid_is_null(uuid); 49 | std::cout << "uuid_null() result = " << retval << std::endl; 50 | 51 | return EXIT_SUCCESS; 52 | } 53 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(automata-cxx LANGUAGES CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_EXTENSIONS OFF) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | 9 | # defines targets and sources 10 | # FIXME add src folder 11 | 12 | # contains an "external" library we will link to 13 | # FIXME add external folder 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from sources in this folder 2 | add_library(...) 3 | 4 | # add this folder to include directories for the project 5 | target_include_directories(conversion 6 | PUBLIC 7 | ${CMAKE_CURRENT_LIST_DIR} 8 | ) 9 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/external/conversion.cpp: -------------------------------------------------------------------------------- 1 | #include "conversion.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::string binary_representation(const int decimal) { 7 | return std::bitset<8>(decimal).to_string(); 8 | } 9 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/external/conversion.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | std::string binary_representation(const int decimal); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(automata-cxx LANGUAGES CXX) 4 | 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_EXTENSIONS OFF) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | 9 | # defines targets and sources 10 | add_subdirectory(src) 11 | 12 | # contains an "external" library we will link to 13 | add_subdirectory(external) 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(conversion) 2 | 3 | target_sources(conversion 4 | PRIVATE 5 | conversion.cpp 6 | PUBLIC 7 | conversion.hpp 8 | ) 9 | 10 | target_include_directories(conversion 11 | PUBLIC 12 | ${CMAKE_CURRENT_LIST_DIR} 13 | ) 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/external/conversion.cpp: -------------------------------------------------------------------------------- 1 | #include "conversion.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::string binary_representation(const int decimal) { 7 | return std::bitset<8>(decimal).to_string(); 8 | } 9 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/external/conversion.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | std::string binary_representation(const int decimal); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(automata main.cpp) 2 | 3 | add_subdirectory(evolution) 4 | add_subdirectory(initial) 5 | add_subdirectory(io) 6 | add_subdirectory(parser) 7 | 8 | target_link_libraries(automata 9 | PRIVATE 10 | conversion 11 | evolution 12 | initial 13 | io 14 | parser 15 | ) 16 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/evolution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(evolution) 2 | 3 | target_sources(evolution 4 | PRIVATE 5 | evolution.cpp 6 | PUBLIC 7 | evolution.hpp 8 | ) 9 | 10 | target_include_directories(evolution 11 | PUBLIC 12 | ${CMAKE_CURRENT_LIST_DIR} 13 | ) 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/evolution/evolution.cpp: -------------------------------------------------------------------------------- 1 | #include "evolution.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::vector evolve(const std::vector row, const std::string rule_binary) { 7 | std::vector result; 8 | 9 | for (auto i = 0; i < row.size(); ++i) { 10 | 11 | auto left = (i == 0 ? row.size() : i) - 1; 12 | auto center = i; 13 | auto right = (i + 1) % row.size(); 14 | 15 | auto ancestors = 4 * row[left] + 2 * row[center] + 1 * row[right]; 16 | ancestors = 7 - ancestors; 17 | 18 | auto new_state = std::stoi(rule_binary.substr(ancestors, 1)); 19 | 20 | result.push_back(new_state); 21 | } 22 | 23 | return result; 24 | } 25 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/evolution/evolution.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | std::vector evolve(const std::vector row, const std::string rule_binary); 7 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/initial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(initial) 2 | 3 | target_sources(initial 4 | PRIVATE 5 | initial.cpp 6 | PUBLIC 7 | initial.hpp 8 | ) 9 | 10 | target_include_directories(initial 11 | PUBLIC 12 | ${CMAKE_CURRENT_LIST_DIR} 13 | ) 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/initial/initial.cpp: -------------------------------------------------------------------------------- 1 | #include "initial.hpp" 2 | 3 | #include 4 | 5 | std::vector initial_distribution(const int length) { 6 | 7 | // we start with a vector which is zeroed out 8 | std::vector result(length, 0); 9 | 10 | // more or less in the middle we place a living cell 11 | result[length / 2] = 1; 12 | 13 | return result; 14 | } 15 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/initial/initial.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | std::vector initial_distribution(const int length); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/io/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(io) 2 | 3 | target_sources(io 4 | PRIVATE 5 | io.cpp 6 | PUBLIC 7 | io.hpp 8 | ) 9 | 10 | target_include_directories(io 11 | PUBLIC 12 | ${CMAKE_CURRENT_LIST_DIR} 13 | ) 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/io/io.cpp: -------------------------------------------------------------------------------- 1 | #include "io.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void print_row(const std::vector row) { 8 | std::for_each(row.begin(), row.end(), [](int const &value) { 9 | std::cout << (value == 1 ? '*' : ' '); 10 | }); 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/io/io.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void print_row(const std::vector row); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "conversion.hpp" 2 | #include "evolution.hpp" 3 | #include "initial.hpp" 4 | #include "io.hpp" 5 | #include "parser.hpp" 6 | 7 | #include 8 | 9 | int main(int argc, char *argv[]) { 10 | 11 | // parse arguments 12 | int length, num_steps, rule_decimal; 13 | std::tie(length, num_steps, rule_decimal) = parse_arguments(argc, argv); 14 | 15 | // print information about parameters 16 | std::cout << "length: " << length << std::endl; 17 | std::cout << "number of steps: " << num_steps << std::endl; 18 | std::cout << "rule: " << rule_decimal << std::endl; 19 | 20 | // obtain binary representation for the rule 21 | std::string rule_binary = binary_representation(rule_decimal); 22 | 23 | // create initial distribution 24 | std::vector row = initial_distribution(length); 25 | 26 | // print initial configuration 27 | print_row(row); 28 | 29 | // the system evolves, print each step 30 | for (int step = 0; step < num_steps; step++) { 31 | row = evolve(row, rule_binary); 32 | print_row(row); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(parser) 2 | 3 | target_sources(parser 4 | PRIVATE 5 | parser.cpp 6 | PUBLIC 7 | parser.hpp 8 | ) 9 | 10 | target_include_directories(parser 11 | PUBLIC 12 | ${CMAKE_CURRENT_LIST_DIR} 13 | ) 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/parser/parser.cpp: -------------------------------------------------------------------------------- 1 | #include "parser.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | std::tuple parse_arguments(int argc, char *argv[]) { 8 | assert(argc == 4 && "program called with wrong number of arguments"); 9 | 10 | auto length = std::stoi(argv[1]); 11 | auto num_steps = std::stoi(argv[2]); 12 | auto rule_decimal = std::stoi(argv[3]); 13 | 14 | return std::make_tuple(length, num_steps, rule_decimal); 15 | } 16 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/solution/src/parser/parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | std::tuple parse_arguments(int argc, char *argv[]); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME add automata executable from main.f90 2 | add_executable(...) 3 | 4 | # FIXME add subdirectories for each sub-library 5 | add_subdirectory(...) 6 | 7 | # FIXME link libraries to the executable 8 | target_link_libraries(...) 9 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/evolution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from the sources in this folder 2 | add_library(...) 3 | 4 | # FIXME add this folder to include directories for this project 5 | target_include_directories(...) 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/evolution/evolution.cpp: -------------------------------------------------------------------------------- 1 | #include "evolution.hpp" 2 | 3 | #include 4 | #include 5 | 6 | std::vector evolve(const std::vector row, const std::string rule_binary) { 7 | std::vector result; 8 | 9 | for (auto i = 0; i < row.size(); ++i) { 10 | 11 | auto left = (i == 0 ? row.size() : i) - 1; 12 | auto center = i; 13 | auto right = (i + 1) % row.size(); 14 | 15 | auto ancestors = 4 * row[left] + 2 * row[center] + 1 * row[right]; 16 | ancestors = 7 - ancestors; 17 | 18 | auto new_state = std::stoi(rule_binary.substr(ancestors, 1)); 19 | 20 | result.push_back(new_state); 21 | } 22 | 23 | return result; 24 | } 25 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/evolution/evolution.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | std::vector evolve(const std::vector row, const std::string rule_binary); 7 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/initial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from the sources in this folder 2 | add_library(...) 3 | 4 | # FIXME add this folder to include directories for this project 5 | target_include_directories(...) 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/initial/initial.cpp: -------------------------------------------------------------------------------- 1 | #include "initial.hpp" 2 | 3 | #include 4 | 5 | std::vector initial_distribution(const int length) { 6 | 7 | // we start with a vector which is zeroed out 8 | std::vector result(length, 0); 9 | 10 | // more or less in the middle we place a living cell 11 | result[length / 2] = 1; 12 | 13 | return result; 14 | } 15 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/initial/initial.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | std::vector initial_distribution(const int length); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/io/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from the sources in this folder 2 | add_library(...) 3 | 4 | # FIXME add this folder to include directories for this project 5 | target_include_directories(...) 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/io/io.cpp: -------------------------------------------------------------------------------- 1 | #include "io.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | void print_row(const std::vector row) { 8 | std::for_each(row.begin(), row.end(), [](int const &value) { 9 | std::cout << (value == 1 ? '*' : ' '); 10 | }); 11 | std::cout << std::endl; 12 | } 13 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/io/io.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void print_row(const std::vector row); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/main.cpp: -------------------------------------------------------------------------------- 1 | #include "conversion.hpp" 2 | #include "evolution.hpp" 3 | #include "initial.hpp" 4 | #include "io.hpp" 5 | #include "parser.hpp" 6 | 7 | #include 8 | 9 | int main(int argc, char *argv[]) { 10 | 11 | // parse arguments 12 | int length, num_steps, rule_decimal; 13 | std::tie(length, num_steps, rule_decimal) = parse_arguments(argc, argv); 14 | 15 | // print information about parameters 16 | std::cout << "length: " << length << std::endl; 17 | std::cout << "number of steps: " << num_steps << std::endl; 18 | std::cout << "rule: " << rule_decimal << std::endl; 19 | 20 | // obtain binary representation for the rule 21 | std::string rule_binary = binary_representation(rule_decimal); 22 | 23 | // create initial distribution 24 | std::vector row = initial_distribution(length); 25 | 26 | // print initial configuration 27 | print_row(row); 28 | 29 | // the system evolves, print each step 30 | for (int step = 0; step < num_steps; step++) { 31 | row = evolve(row, rule_binary); 32 | print_row(row); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from the sources in this folder 2 | add_library(...) 3 | 4 | # FIXME add this folder to include directories for this project 5 | target_include_directories(...) 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/parser/parser.cpp: -------------------------------------------------------------------------------- 1 | #include "parser.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | std::tuple parse_arguments(int argc, char *argv[]) { 8 | assert(argc == 4 && "program called with wrong number of arguments"); 9 | 10 | auto length = std::stoi(argv[1]); 11 | auto num_steps = std::stoi(argv[2]); 12 | auto rule_decimal = std::stoi(argv[3]); 13 | 14 | return std::make_tuple(length, num_steps, rule_decimal); 15 | } 16 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-cxx/src/parser/parser.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | std::tuple parse_arguments(int argc, char *argv[]); 6 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(automata-f LANGUAGES Fortran) 4 | 5 | # defines targets and sources 6 | # FIXME add src folder 7 | 8 | # contains an "external" library we will link to 9 | # FIXME add external folder 10 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME add library 2 | add_library(...) 3 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/external/conversion.f90: -------------------------------------------------------------------------------- 1 | module conversion 2 | 3 | implicit none 4 | public binary_representation 5 | private 6 | 7 | contains 8 | 9 | pure function binary_representation(n_decimal) 10 | integer, intent(in) :: n_decimal 11 | integer :: binary_representation(8) 12 | integer :: pos 13 | integer :: n 14 | 15 | binary_representation = 0 16 | pos = 8 17 | n = n_decimal 18 | do while (n > 0) 19 | binary_representation(pos) = mod(n, 2) 20 | n = (n - binary_representation(pos))/2 21 | pos = pos - 1 22 | end do 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(automata-f LANGUAGES Fortran) 4 | 5 | # defines targets and sources 6 | add_subdirectory(src) 7 | 8 | # contains an "external" library we will link to 9 | add_subdirectory(external) 10 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/external/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(conversion) 2 | 3 | target_sources(conversion 4 | PUBLIC 5 | conversion.f90 6 | ) 7 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/external/conversion.f90: -------------------------------------------------------------------------------- 1 | module conversion 2 | 3 | implicit none 4 | public binary_representation 5 | private 6 | 7 | contains 8 | 9 | pure function binary_representation(n_decimal) 10 | integer, intent(in) :: n_decimal 11 | integer :: binary_representation(8) 12 | integer :: pos 13 | integer :: n 14 | 15 | binary_representation = 0 16 | pos = 8 17 | n = n_decimal 18 | do while (n > 0) 19 | binary_representation(pos) = mod(n, 2) 20 | n = (n - binary_representation(pos))/2 21 | pos = pos - 1 22 | end do 23 | end function 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(automata main.f90) 2 | 3 | add_subdirectory(evolution) 4 | add_subdirectory(initial) 5 | add_subdirectory(io) 6 | add_subdirectory(parser) 7 | 8 | target_link_libraries(automata 9 | PRIVATE 10 | conversion 11 | evolution 12 | initial 13 | io 14 | parser 15 | ) 16 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/evolution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(evolution) 2 | 3 | target_sources(evolution 4 | PRIVATE 5 | empty.f90 6 | ancestors.f90 7 | evolution.f90 8 | ) 9 | 10 | target_include_directories(evolution 11 | INTERFACE 12 | $ 13 | ) 14 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/evolution/ancestors.f90: -------------------------------------------------------------------------------- 1 | module ancestors 2 | 3 | implicit none 4 | public compute_ancestors 5 | private 6 | 7 | contains 8 | 9 | pure integer function compute_ancestors(row, left, center, right) result(i) 10 | integer, intent(in) :: row(:) 11 | integer, intent(in) :: left, center, right 12 | 13 | i = 4*row(left) + 2*row(center) + 1*row(right) 14 | i = 8 - i 15 | end function 16 | 17 | end module 18 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/evolution/empty.f90: -------------------------------------------------------------------------------- 1 | module empty 2 | 3 | implicit none 4 | public empty_subroutine 5 | private 6 | 7 | contains 8 | 9 | subroutine empty_subroutine() 10 | end subroutine 11 | 12 | end module 13 | 14 | 15 | subroutine empty_subroutine_no_interface() 16 | use empty, only: empty_subroutine 17 | call empty_subroutine() 18 | end subroutine 19 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/evolution/evolution.f90: -------------------------------------------------------------------------------- 1 | module evolution 2 | 3 | implicit none 4 | public evolve 5 | private 6 | 7 | contains 8 | 9 | subroutine not_visible() 10 | ! no-op call to demonstrate private/public visibility 11 | call empty_subroutine_no_interface() 12 | end subroutine 13 | 14 | pure subroutine evolve(row, rule_binary) 15 | use ancestors, only: compute_ancestors 16 | 17 | integer, intent(inout) :: row(:) 18 | integer, intent(in) :: rule_binary(8) 19 | integer :: i 20 | integer :: left, center, right 21 | integer :: ancestry 22 | integer, allocatable :: new_row(:) 23 | 24 | allocate(new_row(size(row))) 25 | 26 | do i = 1, size(row) 27 | left = i - 1 28 | center = i 29 | right = i + 1 30 | 31 | if (left < 1) left = left + size(row) 32 | if (right > size(row)) right = right - size(row) 33 | 34 | ancestry = compute_ancestors(row, left, center, right) 35 | new_row(i) = rule_binary(ancestry) 36 | end do 37 | 38 | row = new_row 39 | deallocate(new_row) 40 | 41 | end subroutine 42 | 43 | end module 44 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/initial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(initial) 2 | 3 | target_sources(initial 4 | PRIVATE 5 | initial.f90 6 | ) 7 | 8 | target_include_directories(initial 9 | INTERFACE 10 | $ 11 | ) 12 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/initial/initial.f90: -------------------------------------------------------------------------------- 1 | module initial 2 | 3 | implicit none 4 | public initial_distribution 5 | private 6 | 7 | contains 8 | 9 | pure subroutine initial_distribution(row) 10 | integer, intent(out) :: row(:) 11 | 12 | row = 0 13 | row(size(row)/2) = 1 14 | end subroutine 15 | 16 | end module 17 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/io/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(io) 2 | 3 | target_sources(io 4 | PRIVATE 5 | io.f90 6 | ) 7 | 8 | target_include_directories(io 9 | INTERFACE 10 | $ 11 | ) 12 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/io/io.f90: -------------------------------------------------------------------------------- 1 | module io 2 | 3 | implicit none 4 | public print_row 5 | private 6 | 7 | contains 8 | 9 | subroutine print_row(row) 10 | integer, intent(in) :: row(:) 11 | character(size(row)) :: line 12 | integer :: i 13 | 14 | do i = 1, size(row) 15 | if (row(i) == 1) then 16 | line(i:i) = '*' 17 | else 18 | line(i:i) = ' ' 19 | end if 20 | end do 21 | 22 | print *, line 23 | end subroutine 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/main.f90: -------------------------------------------------------------------------------- 1 | program example 2 | 3 | use parser, only: get_arg_as_int 4 | use conversion, only: binary_representation 5 | use initial, only: initial_distribution 6 | use io, only: print_row 7 | use evolution, only: evolve 8 | 9 | implicit none 10 | 11 | integer :: num_steps 12 | integer :: length 13 | integer :: rule_decimal 14 | integer :: rule_binary(8) 15 | integer, allocatable :: row(:) 16 | integer :: step 17 | 18 | ! parse arguments 19 | length = get_arg_as_int(1) 20 | num_steps = get_arg_as_int(2) 21 | rule_decimal = get_arg_as_int(3) 22 | 23 | ! print information about parameters 24 | print *, "length: ", length 25 | print *, "number of steps: ", num_steps 26 | print *, "rule: ", rule_decimal 27 | 28 | ! obtain binary representation for the rule 29 | rule_binary = binary_representation(rule_decimal) 30 | 31 | ! create initial distribution 32 | allocate(row(length)) 33 | call initial_distribution(row) 34 | 35 | ! print initial configuration 36 | call print_row(row) 37 | 38 | ! the system evolves, print each step 39 | do step = 1, num_steps 40 | call evolve(row, rule_binary) 41 | call print_row(row) 42 | end do 43 | 44 | deallocate(row) 45 | 46 | end program 47 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(parser) 2 | 3 | target_sources(parser 4 | PRIVATE 5 | parser.f90 6 | ) 7 | 8 | target_include_directories(parser 9 | INTERFACE 10 | $ 11 | ) 12 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/solution/src/parser/parser.f90: -------------------------------------------------------------------------------- 1 | module parser 2 | 3 | implicit none 4 | public get_arg_as_int 5 | private 6 | 7 | contains 8 | 9 | integer function get_arg_as_int(n) result(i) 10 | integer, intent(in) :: n 11 | character(len=32) :: arg 12 | 13 | call get_command_argument(n, arg) 14 | read(arg , *) i 15 | end function 16 | 17 | end module 18 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME add automata executable from main.f90 2 | add_executable(...) 3 | 4 | # FIXME add subdirectories for each sub-library 5 | add_subdirectory(...) 6 | 7 | # FIXME link libraries to the executable 8 | target_link_libraries(...) 9 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/evolution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from sources in this folder 2 | add_library(...) 3 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/evolution/ancestors.f90: -------------------------------------------------------------------------------- 1 | module ancestors 2 | 3 | implicit none 4 | public compute_ancestors 5 | private 6 | 7 | contains 8 | 9 | pure integer function compute_ancestors(row, left, center, right) result(i) 10 | integer, intent(in) :: row(:) 11 | integer, intent(in) :: left, center, right 12 | 13 | i = 4*row(left) + 2*row(center) + 1*row(right) 14 | i = 8 - i 15 | end function 16 | 17 | end module 18 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/evolution/empty.f90: -------------------------------------------------------------------------------- 1 | module empty 2 | 3 | implicit none 4 | public empty_subroutine 5 | private 6 | 7 | contains 8 | 9 | subroutine empty_subroutine() 10 | end subroutine 11 | 12 | end module 13 | 14 | 15 | subroutine empty_subroutine_no_interface() 16 | use empty, only: empty_subroutine 17 | call empty_subroutine() 18 | end subroutine 19 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/evolution/evolution.f90: -------------------------------------------------------------------------------- 1 | module evolution 2 | 3 | implicit none 4 | public evolve 5 | private 6 | 7 | contains 8 | 9 | subroutine not_visible() 10 | ! no-op call to demonstrate private/public visibility 11 | call empty_subroutine_no_interface() 12 | end subroutine 13 | 14 | pure subroutine evolve(row, rule_binary) 15 | use ancestors, only: compute_ancestors 16 | 17 | integer, intent(inout) :: row(:) 18 | integer, intent(in) :: rule_binary(8) 19 | integer :: i 20 | integer :: left, center, right 21 | integer :: ancestry 22 | integer, allocatable :: new_row(:) 23 | 24 | allocate(new_row(size(row))) 25 | 26 | do i = 1, size(row) 27 | left = i - 1 28 | center = i 29 | right = i + 1 30 | 31 | if (left < 1) left = left + size(row) 32 | if (right > size(row)) right = right - size(row) 33 | 34 | ancestry = compute_ancestors(row, left, center, right) 35 | new_row(i) = rule_binary(ancestry) 36 | end do 37 | 38 | row = new_row 39 | deallocate(new_row) 40 | 41 | end subroutine 42 | 43 | end module 44 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/initial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from sources in this folder 2 | add_library(...) 3 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/initial/initial.f90: -------------------------------------------------------------------------------- 1 | module initial 2 | 3 | implicit none 4 | public initial_distribution 5 | private 6 | 7 | contains 8 | 9 | pure subroutine initial_distribution(row) 10 | integer, intent(out) :: row(:) 11 | 12 | row = 0 13 | row(size(row)/2) = 1 14 | end subroutine 15 | 16 | end module 17 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/io/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from sources in this folder 2 | add_library(...) 3 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/io/io.f90: -------------------------------------------------------------------------------- 1 | module io 2 | 3 | implicit none 4 | public print_row 5 | private 6 | 7 | contains 8 | 9 | subroutine print_row(row) 10 | integer, intent(in) :: row(:) 11 | character(size(row)) :: line 12 | integer :: i 13 | 14 | do i = 1, size(row) 15 | if (row(i) == 1) then 16 | line(i:i) = '*' 17 | else 18 | line(i:i) = ' ' 19 | end if 20 | end do 21 | 22 | print *, line 23 | end subroutine 24 | 25 | end module 26 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/main.f90: -------------------------------------------------------------------------------- 1 | program example 2 | 3 | use parser, only: get_arg_as_int 4 | use conversion, only: binary_representation 5 | use initial, only: initial_distribution 6 | use io, only: print_row 7 | use evolution, only: evolve 8 | 9 | implicit none 10 | 11 | integer :: num_steps 12 | integer :: length 13 | integer :: rule_decimal 14 | integer :: rule_binary(8) 15 | integer, allocatable :: row(:) 16 | integer :: step 17 | 18 | ! parse arguments 19 | length = get_arg_as_int(1) 20 | num_steps = get_arg_as_int(2) 21 | rule_decimal = get_arg_as_int(3) 22 | 23 | ! print information about parameters 24 | print *, "length: ", length 25 | print *, "number of steps: ", num_steps 26 | print *, "rule: ", rule_decimal 27 | 28 | ! obtain binary representation for the rule 29 | rule_binary = binary_representation(rule_decimal) 30 | 31 | ! create initial distribution 32 | allocate(row(length)) 33 | call initial_distribution(row) 34 | 35 | ! print initial configuration 36 | call print_row(row) 37 | 38 | ! the system evolves, print each step 39 | do step = 1, num_steps 40 | call evolve(row, rule_binary) 41 | call print_row(row) 42 | end do 43 | 44 | deallocate(row) 45 | 46 | end program 47 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/parser/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME create library from sources in this folder 2 | add_library(...) 3 | -------------------------------------------------------------------------------- /content/code/day-2/21_automata-f/src/parser/parser.f90: -------------------------------------------------------------------------------- 1 | module parser 2 | 3 | implicit none 4 | public get_arg_as_int 5 | private 6 | 7 | contains 8 | 9 | integer function get_arg_as_int(n) result(i) 10 | integer, intent(in) :: n 11 | character(len=32) :: arg 12 | 13 | call get_command_argument(n, arg) 14 | read(arg , *) i 15 | end function 16 | 17 | end module 18 | -------------------------------------------------------------------------------- /content/code/day-2/22_taskloop/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(taskloop LANGUAGES CXX) 4 | 5 | add_executable(taskloop taskloop.cpp) 6 | 7 | find_package(OpenMP 4.5 REQUIRED COMPONENTS CXX) 8 | 9 | target_link_libraries(taskloop PRIVATE OpenMP::OpenMP_CXX) 10 | -------------------------------------------------------------------------------- /content/code/day-2/22_taskloop/solution/taskloop.cpp: -------------------------------------------------------------------------------- 1 | // example adapted from 2 | // http://www.openmp.org/wp-content/uploads/openmp-examples-4.5.0.pdf page 85 3 | 4 | #include 5 | #include 6 | 7 | void long_running_task(){ 8 | // do something 9 | std::cout << "long_running_task" << std::endl; 10 | }; 11 | 12 | void loop_body(int i, int j){ 13 | // do something 14 | std::cout << "i = " << i << " j = " << j << std::endl; 15 | }; 16 | 17 | void parallel_work() { 18 | int i, j; 19 | #pragma omp taskgroup 20 | { 21 | #pragma omp task 22 | long_running_task(); // can execute concurrently 23 | 24 | #pragma omp taskloop private(j) grainsize(500) nogroup 25 | for (i = 0; i < 100; i++) { // can execute concurrently 26 | for (j = 0; j < i; j++) { 27 | loop_body(i, j); 28 | } 29 | } 30 | } 31 | } 32 | 33 | int main() { 34 | parallel_work(); 35 | return EXIT_SUCCESS; 36 | } 37 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-cxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(mpi-cxx LANGUAGES CXX) 6 | 7 | set(CMAKE_CXX_STANDARD 14) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | # FIXME find MPI with C++ component 12 | 13 | add_executable(hello-mpi hello-mpi.cpp) 14 | 15 | # FIXME link hello-mpi with the imported targett 16 | target_link_libraries(hello-mpi 17 | ... 18 | ) 19 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-cxx/hello-mpi.cpp: -------------------------------------------------------------------------------- 1 | // Author: Wes Kendall 2 | // Copyright 2011 www.mpitutorial.com 3 | // This code is provided freely with the tutorials on mpitutorial.com. Feel 4 | // free to modify it for your own use. Any distribution of the code must 5 | // either provide a link to www.mpitutorial.com or keep this header intact. 6 | // 7 | // An intro MPI hello world program that uses MPI_Init, MPI_Comm_size, 8 | // MPI_Comm_rank, MPI_Finalize, and MPI_Get_processor_name. 9 | // 10 | 11 | #include 12 | 13 | #include 14 | 15 | int main(int argc, char **argv) { 16 | // Initialize the MPI environment. The two arguments to MPI Init are not 17 | // currently used by MPI implementations, but are there in case future 18 | // implementations might need the arguments. 19 | MPI_Init(NULL, NULL); 20 | 21 | // Get the number of processes 22 | int world_size; 23 | MPI_Comm_size(MPI_COMM_WORLD, &world_size); 24 | 25 | // Get the rank of the process 26 | int world_rank; 27 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 28 | 29 | // Get the name of the processor 30 | char processor_name[MPI_MAX_PROCESSOR_NAME]; 31 | int name_len; 32 | MPI_Get_processor_name(processor_name, &name_len); 33 | 34 | // Print off a hello world message 35 | std::cout << "Hello world from processor " << processor_name << ", rank " 36 | << world_rank << " out of " << world_size << " processors" << std::endl; 37 | 38 | // Finalize the MPI environment. No more MPI calls can be made after this 39 | MPI_Finalize(); 40 | } 41 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(mpi-cxx LANGUAGES CXX) 6 | 7 | set(CMAKE_CXX_STANDARD 14) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | find_package(MPI REQUIRED COMPONENTS CXX) 12 | 13 | add_executable(hello-mpi hello-mpi.cpp) 14 | 15 | target_link_libraries(hello-mpi 16 | PUBLIC 17 | MPI::MPI_CXX 18 | ) 19 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-cxx/solution/hello-mpi.cpp: -------------------------------------------------------------------------------- 1 | // Author: Wes Kendall 2 | // Copyright 2011 www.mpitutorial.com 3 | // This code is provided freely with the tutorials on mpitutorial.com. Feel 4 | // free to modify it for your own use. Any distribution of the code must 5 | // either provide a link to www.mpitutorial.com or keep this header intact. 6 | // 7 | // An intro MPI hello world program that uses MPI_Init, MPI_Comm_size, 8 | // MPI_Comm_rank, MPI_Finalize, and MPI_Get_processor_name. 9 | // 10 | 11 | #include 12 | 13 | #include 14 | 15 | int main(int argc, char **argv) { 16 | // Initialize the MPI environment. The two arguments to MPI Init are not 17 | // currently used by MPI implementations, but are there in case future 18 | // implementations might need the arguments. 19 | MPI_Init(NULL, NULL); 20 | 21 | // Get the number of processes 22 | int world_size; 23 | MPI_Comm_size(MPI_COMM_WORLD, &world_size); 24 | 25 | // Get the rank of the process 26 | int world_rank; 27 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); 28 | 29 | // Get the name of the processor 30 | char processor_name[MPI_MAX_PROCESSOR_NAME]; 31 | int name_len; 32 | MPI_Get_processor_name(processor_name, &name_len); 33 | 34 | // Print off a hello world message 35 | std::cout << "Hello world from processor " << processor_name << ", rank " 36 | << world_rank << " out of " << world_size << " processors" << std::endl; 37 | 38 | // Finalize the MPI environment. No more MPI calls can be made after this 39 | MPI_Finalize(); 40 | } 41 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-f/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(mpi-f LANGUAGES Fortran) 6 | 7 | # FIXME find MPI with Fortran component 8 | 9 | add_executable(hello-mpi hello-mpi.f90) 10 | 11 | # FIXME link hello-mpi with imported target 12 | target_link_libraries(hello-mpi 13 | ... 14 | ) 15 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-f/hello-mpi.f90: -------------------------------------------------------------------------------- 1 | program main 2 | 3 | use mpi 4 | 5 | integer ( kind = 4 ) error 6 | integer ( kind = 4 ) id 7 | integer ( kind = 4 ) p 8 | ! 9 | ! Initialize MPI. 10 | ! 11 | call MPI_Init ( error ) 12 | ! 13 | ! Get the number of processes. 14 | ! 15 | call MPI_Comm_size ( MPI_COMM_WORLD, p, error ) 16 | ! 17 | ! Get the individual process ID. 18 | ! 19 | call MPI_Comm_rank ( MPI_COMM_WORLD, id, error ) 20 | ! 21 | ! Every MPI process will print this message. 22 | ! 23 | write ( *, '(a,i1,2x,a)' ) 'P', id, '"Hello, world!"' 24 | ! 25 | ! Shut down MPI. 26 | ! 27 | call MPI_Finalize ( error ) 28 | end program 29 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-f/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(mpi-f LANGUAGES Fortran) 6 | 7 | find_package(MPI REQUIRED COMPONENTS Fortran) 8 | 9 | add_executable(hello-mpi hello-mpi.f90) 10 | 11 | target_link_libraries(hello-mpi 12 | PRIVATE 13 | MPI::MPI_Fortran 14 | ) 15 | -------------------------------------------------------------------------------- /content/code/day-2/23_mpi-f/solution/hello-mpi.f90: -------------------------------------------------------------------------------- 1 | program main 2 | 3 | use mpi 4 | 5 | integer ( kind = 4 ) error 6 | integer ( kind = 4 ) id 7 | integer ( kind = 4 ) p 8 | ! 9 | ! Initialize MPI. 10 | ! 11 | call MPI_Init ( error ) 12 | ! 13 | ! Get the number of processes. 14 | ! 15 | call MPI_Comm_size ( MPI_COMM_WORLD, p, error ) 16 | ! 17 | ! Get the individual process ID. 18 | ! 19 | call MPI_Comm_rank ( MPI_COMM_WORLD, id, error ) 20 | ! 21 | ! Every MPI process will print this message. 22 | ! 23 | write ( *, '(a,i1,2x,a)' ) 'P', id, '"Hello, world!"' 24 | ! 25 | ! Shut down MPI. 26 | ! 27 | call MPI_Finalize ( error ) 28 | end program 29 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | # FIXME complete the invocation of the project command 4 | project(fortran-cxx ...) 5 | 6 | add_subdirectory(src) 7 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | 3 | project(fortran-cxx LANGUAGES Fortran) 4 | 5 | add_subdirectory(src) 6 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(interfaces) 2 | add_subdirectory(utils) 3 | 4 | add_executable(bt-randomgen-example bt-randomgen-example.f90) 5 | 6 | target_link_libraries(bt-randomgen-example 7 | PRIVATE 8 | bt-randomgen-wrap 9 | utils 10 | ) 11 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/bt-randomgen-example.f90: -------------------------------------------------------------------------------- 1 | program bt_randomgen_example 2 | use, intrinsic :: iso_c_binding, only: c_int & 3 | , c_ptr & 4 | , c_loc 5 | use, intrinsic :: iso_fortran_env, only: output_unit & 6 | , error_unit 7 | use interface_backtrace 8 | use interface_randomgen 9 | use util_strings 10 | 11 | integer(c_int) :: lower, upper 12 | 13 | type(c_ptr), target :: buffer(100) 14 | type(c_ptr) :: c_buf 15 | integer(c_int) :: bt_size 16 | 17 | lower = -2 18 | upper = 42 19 | do i = 1, 20 20 | write(output_unit, '(1X,"Get a random number",1X,I5)') randomgen(lower, upper) 21 | end do 22 | 23 | write(error_unit, '(A)') 'Printing backtrace' 24 | c_buf = c_loc(buffer) 25 | bt_size = backtrace(c_buf, 100) 26 | call backtrace_symbols_fd(c_buf, bt_size, 2) 27 | end program 28 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/interfaces/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # needed to find the backtrace library 2 | enable_language(C) 3 | # needed for the random number generator 4 | enable_language(CXX) 5 | 6 | # verify the compatibility of the C/Fortran and C++/Fortran compilers 7 | include(FortranCInterface) 8 | FortranCInterface_VERIFY(CXX) 9 | 10 | find_package(Backtrace REQUIRED) 11 | 12 | add_library(bt-randomgen-wrap SHARED) 13 | 14 | target_sources(bt-randomgen-wrap 15 | PUBLIC 16 | interface_backtrace.f90 17 | interface_randomgen.f90 18 | PRIVATE 19 | randomgen.cpp 20 | ) 21 | 22 | target_link_libraries(bt-randomgen-wrap 23 | PUBLIC 24 | ${Backtrace_LIBRARIES} 25 | ) 26 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/interfaces/interface_backtrace.f90: -------------------------------------------------------------------------------- 1 | module interface_backtrace 2 | 3 | implicit none 4 | 5 | interface 6 | function backtrace(buffer, size) result(bt) bind(C, name="backtrace") 7 | use, intrinsic :: iso_c_binding, only: c_int, c_ptr 8 | type(c_ptr) :: buffer 9 | integer(c_int), value :: size 10 | integer(c_int) :: bt 11 | end function 12 | 13 | subroutine backtrace_symbols_fd(buffer, size, fd) bind(C, name="backtrace_symbols_fd") 14 | use, intrinsic :: iso_c_binding, only: c_int, c_ptr 15 | type(c_ptr) :: buffer 16 | integer(c_int), value :: size, fd 17 | end subroutine 18 | end interface 19 | 20 | end module 21 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/interfaces/interface_randomgen.f90: -------------------------------------------------------------------------------- 1 | module interface_randomgen 2 | 3 | implicit none 4 | 5 | interface 6 | function randomgen(lower, upper) result(rn) bind(C) 7 | use, intrinsic :: iso_c_binding, only: c_int 8 | integer(c_int), intent(in), value :: lower, upper 9 | integer(c_int) :: rn 10 | end function 11 | end interface 12 | 13 | end module 14 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/interfaces/randomgen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" 4 | int randomgen(int lower, int upper) { 5 | std::random_device rd; 6 | std::mt19937 mt(rd()); 7 | std::uniform_real_distribution dist(lower, upper); 8 | return dist(mt); 9 | } 10 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(utils SHARED) 2 | 3 | target_sources(utils 4 | PUBLIC 5 | util_strings.f90 6 | ) 7 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/solution/src/utils/util_strings.f90: -------------------------------------------------------------------------------- 1 | module util_strings 2 | use, intrinsic :: iso_c_binding, only: c_char, c_null_char 3 | implicit none 4 | 5 | contains 6 | 7 | ! \brief Convert a Fortran string into a C string. 8 | ! \param[in] string_f03 a Fortran character string. 9 | ! \return array_c Null-terminated C string in a character array. 10 | pure function fstring_to_carray(string_f03) result(array_c) 11 | character(len=*), intent(in) :: string_f03 12 | character(kind=c_char) :: array_c(len(string_f03)+1) 13 | 14 | integer :: i 15 | 16 | do i = 1, len(string_f03) 17 | array_c(i) = string_f03(i:i) 18 | end do 19 | array_c(i) = c_null_char 20 | end function 21 | 22 | ! \brief Convert a C string into a Fortran string. 23 | ! \param[in] array_c a null-terminated C string in a character array. 24 | ! \return string_f03 Fortran character string (without null termination). 25 | pure function carray_to_fstring(array_c) result(string_f03) 26 | character(kind=c_char), intent(in) :: array_c(:) 27 | character(len=size(array_c)-1) :: string_f03 28 | 29 | integer :: i 30 | 31 | ! Don't copy any (presumably garbage) from beyond the null character. 32 | string_f03 = '' 33 | do i = 1, size(array_c)-1 34 | if (array_c(i) == c_null_char) exit 35 | string_f03(i:i) = array_c(i) 36 | end do 37 | end function 38 | 39 | end module 40 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(interfaces) 2 | add_subdirectory(utils) 3 | 4 | # FIXME create an executable from the Fortran source file 5 | add_executable(...) 6 | 7 | # FIXME link the Fortran executable to the libraries 8 | target_link_libraries(bt-randomgen-example 9 | PRIVATE 10 | ... 11 | ) 12 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/bt-randomgen-example.f90: -------------------------------------------------------------------------------- 1 | program bt_randomgen_example 2 | use, intrinsic :: iso_c_binding, only: c_int & 3 | , c_ptr & 4 | , c_loc 5 | use, intrinsic :: iso_fortran_env, only: output_unit & 6 | , error_unit 7 | use interface_backtrace 8 | use interface_randomgen 9 | use util_strings 10 | 11 | integer(c_int) :: lower, upper 12 | 13 | type(c_ptr), target :: buffer(100) 14 | type(c_ptr) :: c_buf 15 | integer(c_int) :: bt_size 16 | 17 | lower = -2 18 | upper = 42 19 | do i = 1, 20 20 | write(output_unit, '(1X,"Get a random number",1X,I5)') randomgen(lower, upper) 21 | end do 22 | 23 | write(error_unit, '(A)') 'Printing backtrace' 24 | c_buf = c_loc(buffer) 25 | bt_size = backtrace(c_buf, 100) 26 | call backtrace_symbols_fd(c_buf, bt_size, 2) 27 | end program 28 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/interfaces/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME verify the compatibility of the C/Fortran and C++/Fortran compilers 2 | include(...) 3 | 4 | find_package(Backtrace REQUIRED) 5 | 6 | # FIXME create library from sources 7 | add_library(...) 8 | 9 | # FIXME add sources to library 10 | target_sources(bt-randomgen-wrap 11 | PUBLIC 12 | ... 13 | PRIVATE 14 | ... 15 | ) 16 | 17 | target_link_libraries(bt-randomgen-wrap 18 | PUBLIC 19 | ${Backtrace_LIBRARIES} 20 | ) 21 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/interfaces/interface_backtrace.f90: -------------------------------------------------------------------------------- 1 | module interface_backtrace 2 | 3 | implicit none 4 | 5 | interface 6 | function backtrace(buffer, size) result(bt) bind(C, name="backtrace") 7 | use, intrinsic :: iso_c_binding, only: c_int, c_ptr 8 | type(c_ptr) :: buffer 9 | integer(c_int), value :: size 10 | integer(c_int) :: bt 11 | end function 12 | 13 | subroutine backtrace_symbols_fd(buffer, size, fd) bind(C, name="backtrace_symbols_fd") 14 | use, intrinsic :: iso_c_binding, only: c_int, c_ptr 15 | type(c_ptr) :: buffer 16 | integer(c_int), value :: size, fd 17 | end subroutine 18 | end interface 19 | 20 | end module 21 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/interfaces/interface_randomgen.f90: -------------------------------------------------------------------------------- 1 | module interface_randomgen 2 | 3 | implicit none 4 | 5 | interface 6 | function randomgen(lower, upper) result(rn) bind(C) 7 | use, intrinsic :: iso_c_binding, only: c_int 8 | integer(c_int), intent(in), value :: lower, upper 9 | integer(c_int) :: rn 10 | end function 11 | end interface 12 | 13 | end module 14 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/interfaces/randomgen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern "C" 4 | int randomgen(int lower, int upper) { 5 | std::random_device rd; 6 | std::mt19937 mt(rd()); 7 | std::uniform_real_distribution dist(lower, upper); 8 | return dist(mt); 9 | } 10 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(utils SHARED) 2 | 3 | target_sources(utils 4 | PUBLIC 5 | util_strings.f90 6 | ) 7 | -------------------------------------------------------------------------------- /content/code/day-2/24_fortran-cxx/src/utils/util_strings.f90: -------------------------------------------------------------------------------- 1 | module util_strings 2 | use, intrinsic :: iso_c_binding, only: c_char, c_null_char 3 | implicit none 4 | 5 | contains 6 | 7 | ! \brief Convert a Fortran string into a C string. 8 | ! \param[in] string_f03 a Fortran character string. 9 | ! \return array_c Null-terminated C string in a character array. 10 | pure function fstring_to_carray(string_f03) result(array_c) 11 | character(len=*), intent(in) :: string_f03 12 | character(kind=c_char) :: array_c(len(string_f03)+1) 13 | 14 | integer :: i 15 | 16 | do i = 1, len(string_f03) 17 | array_c(i) = string_f03(i:i) 18 | end do 19 | array_c(i) = c_null_char 20 | end function 21 | 22 | ! \brief Convert a C string into a Fortran string. 23 | ! \param[in] array_c a null-terminated C string in a character array. 24 | ! \return string_f03 Fortran character string (without null termination). 25 | pure function carray_to_fstring(array_c) result(string_f03) 26 | character(kind=c_char), intent(in) :: array_c(:) 27 | character(len=size(array_c)-1) :: string_f03 28 | 29 | integer :: i 30 | 31 | ! Don't copy any (presumably garbage) from beyond the null character. 32 | string_f03 = '' 33 | do i = 1, size(array_c)-1 34 | if (array_c(i) == c_null_char) exit 35 | string_f03(i:i) = array_c(i) 36 | end do 37 | end function 38 | 39 | end module 40 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(cxx-fortran LANGUAGES CXX C Fortran) 6 | 7 | set(CMAKE_CXX_STANDARD 14) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | add_subdirectory(src) 12 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(cxx-fortran LANGUAGES CXX C Fortran) 6 | 7 | set(CMAKE_CXX_STANDARD 14) 8 | set(CMAKE_CXX_EXTENSIONS OFF) 9 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 10 | 11 | add_subdirectory(src) 12 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(math) 2 | 3 | add_executable(linear-algebra) 4 | 5 | target_sources(linear-algebra 6 | PRIVATE 7 | linear-algebra.cpp 8 | ) 9 | 10 | target_link_libraries(linear-algebra 11 | PRIVATE 12 | math 13 | ) 14 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/src/linear-algebra.cpp: -------------------------------------------------------------------------------- 1 | // Original example by Evgenii Rudnyi http://MatrixProgramming.com 2 | // found at: http://matrixprogramming.com/files/code/LAPACK/dgesv.cpp 3 | 4 | #include "CxxBLAS.hpp" 5 | #include "CxxLAPACK.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char **argv) { 12 | if (argc != 2) { 13 | std::cout << "Usage: ./linear-algebra dim" << std::endl; 14 | return EXIT_FAILURE; 15 | } 16 | 17 | // Generate a uniform distribution of real number between -1.0 and 1.0 18 | std::random_device rd; 19 | std::mt19937 mt(rd()); 20 | std::uniform_real_distribution dist(-1.0, 1.0); 21 | 22 | // Allocate matrices and right-hand side vector 23 | int dim = std::atoi(argv[1]); 24 | std::vector A(dim * dim); 25 | std::vector b(dim); 26 | std::vector ipiv(dim); 27 | // Fill matrix and RHS with random numbers between -1.0 and 1.0 28 | for (int r = 0; r < dim; r++) { 29 | for (int c = 0; c < dim; c++) { 30 | A[r + c * dim] = dist(mt); 31 | } 32 | b[r] = dist(mt); 33 | } 34 | 35 | // Scale RHS vector by a random number between -1.0 and 1.0 36 | C_DSCAL(dim, dist(mt), b.data(), 1); 37 | std::cout << "C_DSCAL done" << std::endl; 38 | 39 | // Save matrix and RHS 40 | std::vector A1(A); 41 | std::vector b1(b); 42 | 43 | int info; 44 | info = C_DGESV(dim, 1, A.data(), dim, ipiv.data(), b.data(), dim); 45 | std::cout << "C_DGESV done" << std::endl; 46 | std::cout << "info is " << info << std::endl; 47 | 48 | double eps = 0.0; 49 | for (int i = 0; i < dim; ++i) { 50 | double sum = 0.0; 51 | for (int j = 0; j < dim; ++j) 52 | sum += A1[i + j * dim] * b[j]; 53 | eps += std::abs(b1[i] - sum); 54 | } 55 | std::cout << "check is " << eps << std::endl; 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/src/math/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(BLAS REQUIRED) 2 | find_package(LAPACK REQUIRED) 3 | 4 | include(FortranCInterface) 5 | 6 | FortranCInterface_VERIFY(CXX) 7 | 8 | FortranCInterface_HEADER( 9 | fc_mangle.h 10 | SYMBOLS DSCAL DGESV 11 | ) 12 | 13 | add_library(math) 14 | 15 | target_sources(math 16 | PRIVATE 17 | CxxBLAS.cpp 18 | CxxLAPACK.cpp 19 | ) 20 | 21 | target_include_directories(math 22 | PUBLIC 23 | ${CMAKE_CURRENT_SOURCE_DIR} 24 | ${CMAKE_CURRENT_BINARY_DIR} 25 | ) 26 | 27 | target_link_libraries(math 28 | PUBLIC 29 | LAPACK::LAPACK 30 | ) 31 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/src/math/CxxBLAS.cpp: -------------------------------------------------------------------------------- 1 | // Adapted from Psi4 2 | 3 | #include "CxxBLAS.hpp" 4 | 5 | #include 6 | 7 | // see http://www.netlib.no/netlib/blas/dscal.f 8 | void C_DSCAL(size_t length, double alpha, double *vec, int inc) { 9 | int big_blocks = (int)(length / INT_MAX); 10 | int small_size = (int)(length % INT_MAX); 11 | for (int block = 0; block <= big_blocks; block++) { 12 | double *vec_s = &vec[block * inc * (size_t)INT_MAX]; 13 | signed int length_s = (block == big_blocks) ? small_size : INT_MAX; 14 | DSCAL(&length_s, &alpha, vec_s, &inc); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/src/math/CxxBLAS.hpp: -------------------------------------------------------------------------------- 1 | // resolve mangling, adapted from Psi4 2 | 3 | #pragma once 4 | 5 | #include "fc_mangle.h" 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | extern void DSCAL(int *n, double *alpha, double *vec, int *inc); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | void C_DSCAL(size_t length, double alpha, double *vec, int inc); 20 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/src/math/CxxLAPACK.cpp: -------------------------------------------------------------------------------- 1 | // Adapted from Psi4 2 | 3 | #include "CxxLAPACK.hpp" 4 | 5 | // see http://www.netlib.no/netlib/lapack/double/dgesv.f 6 | int C_DGESV(int n, int nrhs, double *a, int lda, int *ipiv, double *b, int ldb) { 7 | int info; 8 | DGESV(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info); 9 | return info; 10 | } 11 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/solution/src/math/CxxLAPACK.hpp: -------------------------------------------------------------------------------- 1 | // resolve mangling, adapted from Psi4 2 | 3 | #pragma once 4 | 5 | #include "fc_mangle.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | extern int DGESV(int *, int *, double *, int *, int *, double *, int *, int *); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | int C_DGESV(int n, int nrhs, double *a, int lda, int *ipiv, double *b, int ldb); 18 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(math) 2 | 3 | # FIXME create linear-algebra executable 4 | add_executable(...) 5 | 6 | # FIXME add sources to the linear-algebra executable 7 | target_sources(linear-algebra 8 | ... 9 | ) 10 | 11 | # FIXME link libraries to the linear-algebra executable 12 | target_link_libraries(linear-algebra 13 | ... 14 | ) 15 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/src/linear-algebra.cpp: -------------------------------------------------------------------------------- 1 | // Original example by Evgenii Rudnyi http://MatrixProgramming.com 2 | // found at: http://matrixprogramming.com/files/code/LAPACK/dgesv.cpp 3 | 4 | #include "CxxBLAS.hpp" 5 | #include "CxxLAPACK.hpp" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | int main(int argc, char **argv) { 12 | if (argc != 2) { 13 | std::cout << "Usage: ./linear-algebra dim" << std::endl; 14 | return EXIT_FAILURE; 15 | } 16 | 17 | // Generate a uniform distribution of real number between -1.0 and 1.0 18 | std::random_device rd; 19 | std::mt19937 mt(rd()); 20 | std::uniform_real_distribution dist(-1.0, 1.0); 21 | 22 | // Allocate matrices and right-hand side vector 23 | int dim = std::atoi(argv[1]); 24 | std::vector A(dim * dim); 25 | std::vector b(dim); 26 | std::vector ipiv(dim); 27 | // Fill matrix and RHS with random numbers between -1.0 and 1.0 28 | for (int r = 0; r < dim; r++) { 29 | for (int c = 0; c < dim; c++) { 30 | A[r + c * dim] = dist(mt); 31 | } 32 | b[r] = dist(mt); 33 | } 34 | 35 | // Scale RHS vector by a random number between -1.0 and 1.0 36 | C_DSCAL(dim, dist(mt), b.data(), 1); 37 | std::cout << "C_DSCAL done" << std::endl; 38 | 39 | // Save matrix and RHS 40 | std::vector A1(A); 41 | std::vector b1(b); 42 | 43 | int info; 44 | info = C_DGESV(dim, 1, A.data(), dim, ipiv.data(), b.data(), dim); 45 | std::cout << "C_DGESV done" << std::endl; 46 | std::cout << "info is " << info << std::endl; 47 | 48 | double eps = 0.0; 49 | for (int i = 0; i < dim; ++i) { 50 | double sum = 0.0; 51 | for (int j = 0; j < dim; ++j) 52 | sum += A1[i + j * dim] * b[j]; 53 | eps += std::abs(b1[i] - sum); 54 | } 55 | std::cout << "check is " << eps << std::endl; 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/src/math/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(BLAS REQUIRED) 2 | find_package(LAPACK REQUIRED) 3 | 4 | # FIXME include CMake module for C/C++ and Fortran interoperability 5 | include(...) 6 | 7 | # FIXME verify compatibility of compilers 8 | 9 | # FIXME generate Fortran name mangling header 10 | FortranCInterface_HEADER( 11 | ... 12 | SYMBOLS ... 13 | ) 14 | 15 | add_library(math) 16 | 17 | target_sources(math 18 | PRIVATE 19 | CxxBLAS.cpp 20 | CxxLAPACK.cpp 21 | ) 22 | 23 | # FIXME define include directories for dependents on math library 24 | target_include_directories(math 25 | ... 26 | ) 27 | 28 | target_link_libraries(math 29 | PUBLIC 30 | LAPACK::LAPACK 31 | ) 32 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/src/math/CxxBLAS.cpp: -------------------------------------------------------------------------------- 1 | // Adapted from Psi4 2 | 3 | #include "CxxBLAS.hpp" 4 | 5 | #include 6 | 7 | // see http://www.netlib.no/netlib/blas/dscal.f 8 | void C_DSCAL(size_t length, double alpha, double *vec, int inc) { 9 | int big_blocks = (int)(length / INT_MAX); 10 | int small_size = (int)(length % INT_MAX); 11 | for (int block = 0; block <= big_blocks; block++) { 12 | double *vec_s = &vec[block * inc * (size_t)INT_MAX]; 13 | signed int length_s = (block == big_blocks) ? small_size : INT_MAX; 14 | ::DSCAL(&length_s, &alpha, vec_s, &inc); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/src/math/CxxBLAS.hpp: -------------------------------------------------------------------------------- 1 | // resolve mangling, adapted from Psi4 2 | 3 | #pragma once 4 | 5 | #include "fc_mangle.h" 6 | 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | extern void DSCAL(int *n, double *alpha, double *vec, int *inc); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | void C_DSCAL(size_t length, double alpha, double *vec, int inc); 20 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/src/math/CxxLAPACK.cpp: -------------------------------------------------------------------------------- 1 | // Adapted from Psi4 2 | 3 | #include "CxxLAPACK.hpp" 4 | 5 | // see http://www.netlib.no/netlib/lapack/double/dgesv.f 6 | int C_DGESV(int n, int nrhs, double *a, int lda, int *ipiv, double *b, int ldb) { 7 | int info; 8 | ::DGESV(&n, &nrhs, a, &lda, ipiv, b, &ldb, &info); 9 | return info; 10 | } 11 | -------------------------------------------------------------------------------- /content/code/day-2/25_cxx-fortran/src/math/CxxLAPACK.hpp: -------------------------------------------------------------------------------- 1 | // resolve mangling, adapted from Psi4 2 | 3 | #pragma once 4 | 5 | #include "fc_mangle.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | extern int DGESV(int *, int *, double *, int *, int *, double *, int *, int *); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | int C_DGESV(int n, int nrhs, double *a, int lda, int *ipiv, double *b, int ldb); 18 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME set minimum cmake version 2 | 3 | # FIXME project name and language 4 | 5 | # FIXME require C++14 6 | 7 | # FIXME create sum_integers library 8 | 9 | # FIXME create sum_up executable 10 | # FIXME link sum_up executable to sum_integers library 11 | 12 | # enable FetchContent 13 | include(FetchContent) 14 | 15 | # FIXME declare Catch2 content 16 | FetchContent_Declare(... # FIXME name of the content 17 | GIT_REPOSITORY ... # FIXME the repository from which to download the content 18 | GIT_TAG ... # FIXME the tag to download 19 | ) 20 | 21 | # FIXME make content available 22 | FetchContent_MakeAvailable(...) 23 | 24 | # FIXME create cpp_test testing binary 25 | # FIXME link cpp_test against the Catch2 imported target and the sum_integers library 26 | 27 | # enable testing functionality 28 | enable_testing() 29 | 30 | # define test 31 | add_test( 32 | NAME catch_test 33 | COMMAND $ --success 34 | ) 35 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and language 5 | project(more-catch2 LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # example library 13 | add_library(sum_integers sum_integers.cpp) 14 | 15 | # main code 16 | add_executable(sum_up main.cpp) 17 | target_link_libraries(sum_up PRIVATE sum_integers) 18 | 19 | # enable FetchContent 20 | include(FetchContent) 21 | 22 | # declare Catch2 23 | FetchContent_Declare(Catch2 # name of the content 24 | GIT_REPOSITORY https://github.com/catchorg/Catch2.git # the repository 25 | GIT_TAG v2.13.4 # the tag 26 | ) 27 | 28 | # make available 29 | FetchContent_MakeAvailable(Catch2) 30 | 31 | # testing binary 32 | add_executable(cpp_test test.cpp) 33 | target_link_libraries(cpp_test PRIVATE sum_integers Catch2::Catch2) 34 | 35 | # enable testing functionality 36 | enable_testing() 37 | 38 | # define test 39 | add_test( 40 | NAME catch_test 41 | COMMAND $ --success 42 | ) 43 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/solution/main.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | // we assume all arguments are integers and we sum them up 8 | // for simplicity we do not verify the type of arguments 9 | int main(int argc, char *argv[]) { 10 | 11 | std::vector integers; 12 | for (auto i = 1; i < argc; i++) { 13 | integers.push_back(std::stoi(argv[i])); 14 | } 15 | auto sum = sum_integers(integers); 16 | 17 | std::cout << sum << std::endl; 18 | } 19 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/solution/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/solution/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/solution/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | // this tells catch to provide a main() 4 | // only do this in one cpp file 5 | #define CATCH_CONFIG_MAIN 6 | #include 7 | 8 | #include 9 | 10 | TEST_CASE("Sum of integers for a short vector", "[short]") { 11 | auto integers = {1, 2, 3, 4, 5}; 12 | REQUIRE(sum_integers(integers) == 15); 13 | } 14 | 15 | TEST_CASE("Sum of integers for a longer vector", "[long]") { 16 | std::vector integers; 17 | for (int i = 1; i < 1001; ++i) { 18 | integers.push_back(i); 19 | } 20 | REQUIRE(sum_integers(integers) == 500500); 21 | } 22 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/sum_integers.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers) { 6 | auto sum = 0; 7 | for (auto i : integers) { 8 | sum += i; 9 | } 10 | return sum; 11 | } 12 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/sum_integers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | int sum_integers(const std::vector integers); 6 | -------------------------------------------------------------------------------- /content/code/day-2/26_more-catch2/test.cpp: -------------------------------------------------------------------------------- 1 | #include "sum_integers.hpp" 2 | 3 | // this tells catch to provide a main() 4 | // only do this in one cpp file 5 | #define CATCH_CONFIG_MAIN 6 | #include 7 | 8 | #include 9 | 10 | TEST_CASE("Sum of integers for a short vector", "[short]") { 11 | auto integers = {1, 2, 3, 4, 5}; 12 | REQUIRE(sum_integers(integers) == 15); 13 | } 14 | 15 | TEST_CASE("Sum of integers for a longer vector", "[long]") { 16 | std::vector integers; 17 | for (int i = 1; i < 1001; ++i) { 18 | integers.push_back(i); 19 | } 20 | REQUIRE(sum_integers(integers) == 500500); 21 | } 22 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/account/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # FIXME enable FetchContent 2 | include(...) 3 | 4 | # FIXME declare and make available pybind11 external content 5 | FetchContent_Declare(...) 6 | 7 | # use pybind11_add_module 8 | pybind11_add_module(account) 9 | 10 | # FIXME add sources to account target 11 | target_sources(account 12 | ... 13 | ) 14 | 15 | # define test 16 | add_test( 17 | NAME 18 | python_test 19 | COMMAND 20 | ${CMAKE_COMMAND} -E env ACCOUNT_MODULE_PATH=$ 21 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py 22 | ) 23 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/account/account.cpp: -------------------------------------------------------------------------------- 1 | #include "account.hpp" 2 | 3 | Account::Account() { balance = 0.0; } 4 | 5 | Account::~Account() {} 6 | 7 | void Account::deposit(const double amount) { balance += amount; } 8 | 9 | void Account::withdraw(const double amount) { balance -= amount; } 10 | 11 | double Account::get_balance() const { return balance; } 12 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/account/account.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Account { 6 | public: 7 | Account(); 8 | ~Account(); 9 | 10 | void deposit(const double amount); 11 | void withdraw(const double amount); 12 | double get_balance() const; 13 | 14 | private: 15 | double balance; 16 | }; 17 | 18 | namespace py = pybind11; 19 | 20 | PYBIND11_MODULE(account, m) { 21 | py::class_(m, "Account") 22 | .def(py::init()) 23 | .def("deposit", &Account::deposit) 24 | .def("withdraw", &Account::withdraw) 25 | .def("get_balance", &Account::get_balance); 26 | } 27 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/account/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.getenv('ACCOUNT_MODULE_PATH')) 4 | 5 | from account import Account # isort: skip 6 | 7 | account1 = Account() 8 | 9 | account1.deposit(100.0) 10 | account1.deposit(100.0) 11 | 12 | account2 = Account() 13 | 14 | account2.deposit(200.0) 15 | account2.deposit(200.0) 16 | 17 | account1.withdraw(50.0) 18 | 19 | assert account1.get_balance() == 150.0 20 | assert account2.get_balance() == 400.0 21 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # define minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and supported language 5 | project(cxx-python LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # find Python interpreter and header files 13 | find_package(Python 3.6 REQUIRED COMPONENTS Interpreter Development) 14 | 15 | # turn on testing 16 | enable_testing() 17 | 18 | add_subdirectory(account) 19 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/solution/account/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(FetchContent) 2 | 3 | FetchContent_Declare(pybind11 4 | URL https://github.com/pybind/pybind11/archive/v2.6.2.tar.gz 5 | ) 6 | 7 | FetchContent_MakeAvailable(pybind11) 8 | 9 | # use pybind11_add_module 10 | pybind11_add_module(account) 11 | 12 | # add sources 13 | target_sources(account 14 | PRIVATE 15 | account.cpp 16 | ) 17 | 18 | # define test 19 | add_test( 20 | NAME 21 | python_test 22 | COMMAND 23 | ${CMAKE_COMMAND} -E env ACCOUNT_MODULE_PATH=$ 24 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test.py 25 | ) 26 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/solution/account/account.cpp: -------------------------------------------------------------------------------- 1 | #include "account.hpp" 2 | 3 | Account::Account() { balance = 0.0; } 4 | 5 | Account::~Account() {} 6 | 7 | void Account::deposit(const double amount) { balance += amount; } 8 | 9 | void Account::withdraw(const double amount) { balance -= amount; } 10 | 11 | double Account::get_balance() const { return balance; } 12 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/solution/account/account.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class Account { 6 | public: 7 | Account(); 8 | ~Account(); 9 | 10 | void deposit(const double amount); 11 | void withdraw(const double amount); 12 | double get_balance() const; 13 | 14 | private: 15 | double balance; 16 | }; 17 | 18 | namespace py = pybind11; 19 | 20 | PYBIND11_MODULE(account, m) { 21 | py::class_(m, "Account") 22 | .def(py::init()) 23 | .def("deposit", &Account::deposit) 24 | .def("withdraw", &Account::withdraw) 25 | .def("get_balance", &Account::get_balance); 26 | } 27 | -------------------------------------------------------------------------------- /content/code/day-2/27_cxx-pybind11/solution/account/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.getenv('ACCOUNT_MODULE_PATH')) 4 | 5 | from account import Account # isort: skip 6 | 7 | account1 = Account() 8 | 9 | account1.deposit(100.0) 10 | account1.deposit(100.0) 11 | 12 | account2 = Account() 13 | 14 | account2.deposit(200.0) 15 | account2.deposit(200.0) 16 | 17 | account1.withdraw(50.0) 18 | 19 | assert account1.get_balance() == 150.0 20 | assert account2.get_balance() == 400.0 21 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # define minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # FIXME declare a project using CXX 5 | project(bank ...) 6 | 7 | # FIXME require python package. We will need the interpreter and development 8 | # components 9 | find_package(Python ...) 10 | 11 | # FIXME add account subdirectory 12 | add_subdirectory(...) 13 | 14 | # FIXME turn on testing 15 | ... 16 | 17 | # copy test.py to root build folder 18 | file(COPY account/test.py DESTINATION ${PROJECT_BINARY_DIR}) 19 | 20 | # FIXME define test to run test.py 21 | add_test( 22 | NAME 23 | ... 24 | COMMAND 25 | ${Python_EXECUTABLE} ... 26 | ) 27 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # create folder for generated code 2 | file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/generated) 3 | 4 | # Call CFFI to generate bindings source file _pyaccount.c 5 | add_custom_command( 6 | OUTPUT 7 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 8 | COMMAND 9 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 10 | MAIN_DEPENDENCY 11 | ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 12 | DEPENDS 13 | ${CMAKE_CURRENT_LIST_DIR}/account.h 14 | WORKING_DIRECTORY 15 | ${PROJECT_BINARY_DIR}/generated 16 | ) 17 | 18 | add_custom_target( 19 | pyaccount-builder 20 | ALL 21 | DEPENDS 22 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 23 | ) 24 | 25 | # FIXME add python module from C++ implementation and generated C wrapper 26 | Python_add_library(_pyaccount 27 | MODULE 28 | ... 29 | ) 30 | 31 | # add dependency between _pyaccount target and pyaccount-builder custom target 32 | add_dependencies(_pyaccount pyaccount-builder) 33 | 34 | target_include_directories(_pyaccount 35 | PRIVATE 36 | ${CMAKE_CURRENT_LIST_DIR} # where account.h lives 37 | ${CMAKE_CURRENT_BINARY_DIR} # where account_export.h lives 38 | ) 39 | 40 | # copy __init__.py to build folder 41 | file(COPY __init__.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 42 | 43 | # generate account_export.h 44 | include(GenerateExportHeader) 45 | generate_export_header(_pyaccount 46 | BASE_NAME account 47 | ) 48 | 49 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/__init__.py: -------------------------------------------------------------------------------- 1 | from ._pyaccount import ffi, lib 2 | 3 | # we change names to obtain a more pythonic API 4 | new = lib.account_new 5 | free = lib.account_free 6 | deposit = lib.account_deposit 7 | withdraw = lib.account_withdraw 8 | get_balance = lib.account_get_balance 9 | 10 | __version__ = "0.0" 11 | 12 | __all__ = [ 13 | "__version__", 14 | "new", 15 | "free", 16 | "deposit", 17 | "withdraw", 18 | "get_balance", 19 | ] 20 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/account.cpp: -------------------------------------------------------------------------------- 1 | #include "account.hpp" 2 | 3 | #include 4 | 5 | Account::Account() { 6 | balance = 0.0; 7 | is_initialized = true; 8 | } 9 | 10 | Account::~Account() { 11 | assert(is_initialized); 12 | is_initialized = false; 13 | } 14 | 15 | void Account::deposit(const double amount) { 16 | assert(is_initialized); 17 | balance += amount; 18 | } 19 | 20 | void Account::withdraw(const double amount) { 21 | assert(is_initialized); 22 | balance -= amount; 23 | } 24 | 25 | double Account::get_balance() const { 26 | assert(is_initialized); 27 | return balance; 28 | } 29 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/account.h: -------------------------------------------------------------------------------- 1 | /* CFFI would issue warning with pragma once */ 2 | #ifndef ACCOUNT_H_INCLUDED 3 | #define ACCOUNT_H_INCLUDED 4 | 5 | #ifndef ACCOUNT_API 6 | #include "account_export.h" 7 | #define ACCOUNT_API ACCOUNT_EXPORT 8 | #endif 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | struct account_context; 15 | typedef struct account_context account_context_t; 16 | 17 | ACCOUNT_API 18 | account_context_t *account_new(); 19 | 20 | ACCOUNT_API 21 | void account_free(account_context_t *context); 22 | 23 | ACCOUNT_API 24 | void account_deposit(account_context_t *context, const double amount); 25 | 26 | ACCOUNT_API 27 | void account_withdraw(account_context_t *context, const double amount); 28 | 29 | ACCOUNT_API 30 | double account_get_balance(const account_context_t *context); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif /* ACCOUNT_H_INCLUDED */ 37 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/account.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Account { 4 | public: 5 | Account(); 6 | ~Account(); 7 | 8 | void deposit(const double amount); 9 | void withdraw(const double amount); 10 | double get_balance() const; 11 | 12 | private: 13 | double balance; 14 | bool is_initialized; 15 | }; 16 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/c_cpp_interface.cpp: -------------------------------------------------------------------------------- 1 | #include "account.h" 2 | #include "account.hpp" 3 | 4 | #define AS_TYPE(Type, Obj) reinterpret_cast(Obj) 5 | #define AS_CTYPE(Type, Obj) reinterpret_cast(Obj) 6 | 7 | account_context_t *account_new() { 8 | return AS_TYPE(account_context_t, new Account()); 9 | } 10 | 11 | void account_free(account_context_t *context) { delete AS_TYPE(Account, context); } 12 | 13 | void account_deposit(account_context_t *context, const double amount) { 14 | return AS_TYPE(Account, context)->deposit(amount); 15 | } 16 | 17 | void account_withdraw(account_context_t *context, const double amount) { 18 | return AS_TYPE(Account, context)->withdraw(amount); 19 | } 20 | 21 | double account_get_balance(const account_context_t *context) { 22 | return AS_CTYPE(Account, context)->get_balance(); 23 | } 24 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/cffi_builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pathlib import Path 4 | from subprocess import check_output 5 | 6 | from cffi import FFI 7 | 8 | ffibuilder = FFI() 9 | 10 | definitions = ["-DACCOUNT_API=", "-DACCOUNT_NOINCLUDE"] 11 | header = Path(__file__).resolve().parent / "account.h" 12 | command = ["cc", "-E"] + definitions + [str(header)] 13 | interface = check_output(command).decode("utf-8") 14 | 15 | # remove possible \r characters on windows which 16 | # would confuse cdef 17 | _interface = [l.strip("\r") for l in interface.split("\n")] 18 | 19 | # cdef() expects a single string declaring the C types, functions and 20 | # globals needed to use the shared object. It must be in valid C syntax. 21 | ffibuilder.cdef("\n".join(_interface)) 22 | 23 | # set_source() gives the name of the python extension module to 24 | # produce, and some C source code as a string. This C code needs 25 | # to make the declared functions, types and globals available, 26 | # so it is often just the "#include". 27 | ffibuilder.set_source( 28 | "_pyaccount", 29 | """ 30 | #include "account.h" 31 | """, 32 | ) 33 | 34 | ffibuilder.emit_c_code("_pyaccount.c") 35 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/account/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.getenv('ACCOUNT_MODULE_PATH')) 4 | 5 | import account # isort: skip 6 | 7 | account1 = account.new() 8 | 9 | account.deposit(account1, 100.0) 10 | account.deposit(account1, 100.0) 11 | 12 | account2 = account.new() 13 | 14 | account.deposit(account2, 200.0) 15 | account.deposit(account2, 200.0) 16 | 17 | account.withdraw(account1, 50.0) 18 | 19 | assert account.get_balance(account1) == 150.0 20 | account.free(account1) 21 | 22 | assert account.get_balance(account2) == 400.0 23 | account.free(account2) 24 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # define minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and supported language 5 | project(bank LANGUAGES CXX C) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # require python 13 | find_package(Python 3.6 REQUIRED Interpreter Development) 14 | 15 | # interface and sources 16 | add_subdirectory(account) 17 | 18 | # turn on testing 19 | enable_testing() 20 | 21 | # copy test.py to root build folder 22 | file(COPY account/test.py DESTINATION ${PROJECT_BINARY_DIR}) 23 | 24 | # define test 25 | add_test( 26 | NAME 27 | python_test 28 | COMMAND 29 | ${Python_EXECUTABLE} ${PROJECT_BINARY_DIR}/test.py 30 | ) 31 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # create folder for generated code 2 | file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/generated) 3 | 4 | # Call CFFI to generate bindings source file _pyaccount.c 5 | add_custom_command( 6 | OUTPUT 7 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 8 | COMMAND 9 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 10 | MAIN_DEPENDENCY 11 | ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 12 | DEPENDS 13 | ${CMAKE_CURRENT_LIST_DIR}/account.h 14 | WORKING_DIRECTORY 15 | ${PROJECT_BINARY_DIR}/generated 16 | ) 17 | 18 | add_custom_target( 19 | pyaccount-builder 20 | ALL 21 | DEPENDS 22 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 23 | ) 24 | 25 | # add python module from Fortran implementation and generated C wrapper 26 | Python_add_library(_pyaccount 27 | MODULE 28 | c_cpp_interface.cpp 29 | account.cpp 30 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 31 | ) 32 | 33 | # add dependency between _pyaccount target and pyaccount-builder custom target 34 | add_dependencies(_pyaccount pyaccount-builder) 35 | 36 | target_include_directories(_pyaccount 37 | PRIVATE 38 | ${CMAKE_CURRENT_LIST_DIR} # where account.h lives 39 | ${CMAKE_CURRENT_BINARY_DIR} # where account_export.h lives 40 | ) 41 | 42 | # copy __init__.py to build folder 43 | file(COPY __init__.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 44 | 45 | # generate account_export.h 46 | include(GenerateExportHeader) 47 | generate_export_header(_pyaccount 48 | BASE_NAME account 49 | ) 50 | 51 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/__init__.py: -------------------------------------------------------------------------------- 1 | from ._pyaccount import ffi, lib 2 | 3 | # we change names to obtain a more pythonic API 4 | new = lib.account_new 5 | free = lib.account_free 6 | deposit = lib.account_deposit 7 | withdraw = lib.account_withdraw 8 | get_balance = lib.account_get_balance 9 | 10 | __version__ = "0.0" 11 | 12 | __all__ = [ 13 | "__version__", 14 | "new", 15 | "free", 16 | "deposit", 17 | "withdraw", 18 | "get_balance", 19 | ] 20 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/account.cpp: -------------------------------------------------------------------------------- 1 | #include "account.hpp" 2 | 3 | #include 4 | 5 | Account::Account() { 6 | balance = 0.0; 7 | is_initialized = true; 8 | } 9 | 10 | Account::~Account() { 11 | assert(is_initialized); 12 | is_initialized = false; 13 | } 14 | 15 | void Account::deposit(const double amount) { 16 | assert(is_initialized); 17 | balance += amount; 18 | } 19 | 20 | void Account::withdraw(const double amount) { 21 | assert(is_initialized); 22 | balance -= amount; 23 | } 24 | 25 | double Account::get_balance() const { 26 | assert(is_initialized); 27 | return balance; 28 | } 29 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/account.h: -------------------------------------------------------------------------------- 1 | /* CFFI would issue warning with pragma once */ 2 | #ifndef ACCOUNT_H_INCLUDED 3 | #define ACCOUNT_H_INCLUDED 4 | 5 | #ifndef ACCOUNT_API 6 | #include "account_export.h" 7 | #define ACCOUNT_API ACCOUNT_EXPORT 8 | #endif 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | struct account_context; 15 | typedef struct account_context account_context_t; 16 | 17 | ACCOUNT_API 18 | account_context_t *account_new(); 19 | 20 | ACCOUNT_API 21 | void account_free(account_context_t *context); 22 | 23 | ACCOUNT_API 24 | void account_deposit(account_context_t *context, const double amount); 25 | 26 | ACCOUNT_API 27 | void account_withdraw(account_context_t *context, const double amount); 28 | 29 | ACCOUNT_API 30 | double account_get_balance(const account_context_t *context); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif /* ACCOUNT_H_INCLUDED */ 37 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/account.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Account { 4 | public: 5 | Account(); 6 | ~Account(); 7 | 8 | void deposit(const double amount); 9 | void withdraw(const double amount); 10 | double get_balance() const; 11 | 12 | private: 13 | double balance; 14 | bool is_initialized; 15 | }; 16 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/c_cpp_interface.cpp: -------------------------------------------------------------------------------- 1 | #include "account.h" 2 | #include "account.hpp" 3 | 4 | #define AS_TYPE(Type, Obj) reinterpret_cast(Obj) 5 | #define AS_CTYPE(Type, Obj) reinterpret_cast(Obj) 6 | 7 | account_context_t *account_new() { 8 | return AS_TYPE(account_context_t, new Account()); 9 | } 10 | 11 | void account_free(account_context_t *context) { delete AS_TYPE(Account, context); } 12 | 13 | void account_deposit(account_context_t *context, const double amount) { 14 | return AS_TYPE(Account, context)->deposit(amount); 15 | } 16 | 17 | void account_withdraw(account_context_t *context, const double amount) { 18 | return AS_TYPE(Account, context)->withdraw(amount); 19 | } 20 | 21 | double account_get_balance(const account_context_t *context) { 22 | return AS_CTYPE(Account, context)->get_balance(); 23 | } 24 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/cffi_builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pathlib import Path 4 | from subprocess import check_output 5 | 6 | from cffi import FFI 7 | 8 | ffibuilder = FFI() 9 | 10 | definitions = ["-DACCOUNT_API=", "-DACCOUNT_NOINCLUDE"] 11 | header = Path(__file__).resolve().parent / "account.h" 12 | command = ["cc", "-E"] + definitions + [str(header)] 13 | interface = check_output(command).decode("utf-8") 14 | 15 | # remove possible \r characters on windows which 16 | # would confuse cdef 17 | _interface = [l.strip("\r") for l in interface.split("\n")] 18 | 19 | # cdef() expects a single string declaring the C types, functions and 20 | # globals needed to use the shared object. It must be in valid C syntax. 21 | ffibuilder.cdef("\n".join(_interface)) 22 | 23 | # set_source() gives the name of the python extension module to 24 | # produce, and some C source code as a string. This C code needs 25 | # to make the declared functions, types and globals available, 26 | # so it is often just the "#include". 27 | ffibuilder.set_source( 28 | "_pyaccount", 29 | """ 30 | #include "account.h" 31 | """, 32 | ) 33 | 34 | ffibuilder.emit_c_code("_pyaccount.c") 35 | -------------------------------------------------------------------------------- /content/code/day-2/28_cxx-cffi/solution/account/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.getenv('ACCOUNT_MODULE_PATH')) 4 | 5 | import account # isort: skip 6 | 7 | account1 = account.new() 8 | 9 | account.deposit(account1, 100.0) 10 | account.deposit(account1, 100.0) 11 | 12 | account2 = account.new() 13 | 14 | account.deposit(account2, 200.0) 15 | account.deposit(account2, 200.0) 16 | 17 | account.withdraw(account1, 50.0) 18 | 19 | assert account.get_balance(account1) == 150.0 20 | account.free(account1) 21 | 22 | assert account.get_balance(account2) == 400.0 23 | account.free(account2) 24 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # define minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # FIXME declare a project using Fortran and C 5 | project(bank ...) 6 | 7 | # FIXME require python package. We will need the interpreter and development 8 | # components 9 | find_package(Python ...) 10 | 11 | # FIXME add account subdirectory 12 | add_subdirectory(...) 13 | 14 | # FIXME turn on testing 15 | ... 16 | 17 | # copy test.py to root build folder 18 | file(COPY account/test.py DESTINATION ${PROJECT_BINARY_DIR}) 19 | 20 | # FIXME define test to run test.py 21 | add_test( 22 | NAME 23 | ... 24 | COMMAND 25 | ${Python_EXECUTABLE} ... 26 | ) 27 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/account/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # create folder for generated code 2 | file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/generated) 3 | 4 | # Call CFFI to generate bindings source file _pyaccount.c 5 | add_custom_command( 6 | OUTPUT 7 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 8 | COMMAND 9 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 10 | MAIN_DEPENDENCY 11 | ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 12 | DEPENDS 13 | ${CMAKE_CURRENT_LIST_DIR}/account.h 14 | WORKING_DIRECTORY 15 | ${PROJECT_BINARY_DIR}/generated 16 | ) 17 | 18 | add_custom_target( 19 | pyaccount-builder 20 | ALL 21 | DEPENDS 22 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 23 | ) 24 | 25 | # FIXME add python module from Fortran implementation and generated C wrapper 26 | Python_add_library(_pyaccount 27 | MODULE 28 | ... 29 | ) 30 | 31 | # add dependency between _pyaccount target and pyaccount-builder custom target 32 | add_dependencies(_pyaccount pyaccount-builder) 33 | 34 | target_include_directories(_pyaccount 35 | PRIVATE 36 | ${CMAKE_CURRENT_LIST_DIR} # where account.h lives 37 | ${CMAKE_CURRENT_BINARY_DIR} # where account_export.h lives 38 | ) 39 | 40 | # copy __init__.py to build folder 41 | file(COPY __init__.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 42 | 43 | # generate account_export.h 44 | include(GenerateExportHeader) 45 | generate_export_header(_pyaccount 46 | BASE_NAME account 47 | ) 48 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/account/__init__.py: -------------------------------------------------------------------------------- 1 | from ._pyaccount import ffi, lib 2 | 3 | # we change names to obtain a more pythonic API 4 | new = lib.account_new 5 | free = lib.account_free 6 | deposit = lib.account_deposit 7 | withdraw = lib.account_withdraw 8 | get_balance = lib.account_get_balance 9 | 10 | __version__ = "0.0" 11 | 12 | __all__ = [ 13 | "__version__", 14 | "new", 15 | "free", 16 | "deposit", 17 | "withdraw", 18 | "get_balance", 19 | ] 20 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/account/account.h: -------------------------------------------------------------------------------- 1 | /* CFFI would issue warning with pragma once */ 2 | #ifndef ACCOUNT_H_INCLUDED 3 | #define ACCOUNT_H_INCLUDED 4 | 5 | #ifndef ACCOUNT_API 6 | #include "account_export.h" 7 | #define ACCOUNT_API ACCOUNT_EXPORT 8 | #endif 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | struct account_context; 15 | typedef struct account_context account_context_t; 16 | 17 | ACCOUNT_API 18 | account_context_t *account_new(); 19 | 20 | ACCOUNT_API 21 | void account_free(account_context_t *context); 22 | 23 | ACCOUNT_API 24 | void account_deposit(account_context_t *context, const double amount); 25 | 26 | ACCOUNT_API 27 | void account_withdraw(account_context_t *context, const double amount); 28 | 29 | ACCOUNT_API 30 | double account_get_balance(const account_context_t *context); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif /* ACCOUNT_H_INCLUDED */ 37 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/account/cffi_builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pathlib import Path 4 | from subprocess import check_output 5 | 6 | from cffi import FFI 7 | 8 | ffibuilder = FFI() 9 | 10 | definitions = ["-DACCOUNT_API=", "-DACCOUNT_NOINCLUDE"] 11 | header = Path(__file__).resolve().parent / "account.h" 12 | command = ["cc", "-E"] + definitions + [str(header)] 13 | interface = check_output(command).decode("utf-8") 14 | 15 | # remove possible \r characters on windows which 16 | # would confuse cdef 17 | _interface = [l.strip("\r") for l in interface.split("\n")] 18 | 19 | # cdef() expects a single string declaring the C types, functions and 20 | # globals needed to use the shared object. It must be in valid C syntax. 21 | ffibuilder.cdef("\n".join(_interface)) 22 | 23 | # set_source() gives the name of the python extension module to 24 | # produce, and some C source code as a string. This C code needs 25 | # to make the declared functions, types and globals available, 26 | # so it is often just the "#include". 27 | ffibuilder.set_source( 28 | "_pyaccount", 29 | """ 30 | #include "account.h" 31 | """, 32 | ) 33 | 34 | ffibuilder.emit_c_code("_pyaccount.c") 35 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/account/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.getenv('ACCOUNT_MODULE_PATH')) 4 | 5 | import account # isort: skip 6 | 7 | account1 = account.new() 8 | 9 | account.deposit(account1, 100.0) 10 | account.deposit(account1, 100.0) 11 | 12 | account2 = account.new() 13 | 14 | account.deposit(account2, 200.0) 15 | account.deposit(account2, 200.0) 16 | 17 | account.withdraw(account1, 50.0) 18 | 19 | assert account.get_balance(account1) == 150.0 20 | account.free(account1) 21 | 22 | assert account.get_balance(account2) == 400.0 23 | account.free(account2) 24 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # define minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and supported languages 5 | project(bank LANGUAGES Fortran C) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # require python 13 | find_package(Python 3.6 REQUIRED Interpreter Development) 14 | 15 | # interface and sources 16 | add_subdirectory(account) 17 | 18 | # turn on testing 19 | enable_testing() 20 | 21 | # copy test.py to root build folder 22 | file(COPY account/test.py DESTINATION ${PROJECT_BINARY_DIR}) 23 | 24 | # define test 25 | add_test( 26 | NAME 27 | python_test 28 | COMMAND 29 | ${Python_EXECUTABLE} ${PROJECT_BINARY_DIR}/test.py 30 | ) 31 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/solution/account/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # create folder for generated code 2 | file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/generated) 3 | 4 | # Call CFFI to generate bindings source file _pyaccount.c 5 | add_custom_command( 6 | OUTPUT 7 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 8 | COMMAND 9 | ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 10 | MAIN_DEPENDENCY 11 | ${CMAKE_CURRENT_LIST_DIR}/cffi_builder.py 12 | DEPENDS 13 | ${CMAKE_CURRENT_LIST_DIR}/account.h 14 | WORKING_DIRECTORY 15 | ${PROJECT_BINARY_DIR}/generated 16 | ) 17 | 18 | add_custom_target( 19 | pyaccount-builder 20 | ALL 21 | DEPENDS 22 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 23 | ) 24 | 25 | # add python module from Fortran implementation and generated C wrapper 26 | Python_add_library(_pyaccount 27 | MODULE 28 | account.f90 29 | ${PROJECT_BINARY_DIR}/generated/_pyaccount.c 30 | ) 31 | 32 | # add dependency between _pyaccount target and pyaccount-builder custom target 33 | add_dependencies(_pyaccount pyaccount-builder) 34 | 35 | target_include_directories(_pyaccount 36 | PRIVATE 37 | ${CMAKE_CURRENT_LIST_DIR} # where account.h lives 38 | ${CMAKE_CURRENT_BINARY_DIR} # where account_export.h lives 39 | ) 40 | 41 | # copy __init__.py to build folder 42 | file(COPY __init__.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) 43 | 44 | # generate account_export.h 45 | include(GenerateExportHeader) 46 | generate_export_header(_pyaccount 47 | BASE_NAME account 48 | ) 49 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/solution/account/__init__.py: -------------------------------------------------------------------------------- 1 | from ._pyaccount import ffi, lib 2 | 3 | # we change names to obtain a more pythonic API 4 | new = lib.account_new 5 | free = lib.account_free 6 | deposit = lib.account_deposit 7 | withdraw = lib.account_withdraw 8 | get_balance = lib.account_get_balance 9 | 10 | __version__ = "0.0" 11 | 12 | __all__ = [ 13 | "__version__", 14 | "new", 15 | "free", 16 | "deposit", 17 | "withdraw", 18 | "get_balance", 19 | ] 20 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/solution/account/account.h: -------------------------------------------------------------------------------- 1 | /* CFFI would issue warning with pragma once */ 2 | #ifndef ACCOUNT_H_INCLUDED 3 | #define ACCOUNT_H_INCLUDED 4 | 5 | #ifndef ACCOUNT_API 6 | #include "account_export.h" 7 | #define ACCOUNT_API ACCOUNT_EXPORT 8 | #endif 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | struct account_context; 15 | typedef struct account_context account_context_t; 16 | 17 | ACCOUNT_API 18 | account_context_t *account_new(); 19 | 20 | ACCOUNT_API 21 | void account_free(account_context_t *context); 22 | 23 | ACCOUNT_API 24 | void account_deposit(account_context_t *context, const double amount); 25 | 26 | ACCOUNT_API 27 | void account_withdraw(account_context_t *context, const double amount); 28 | 29 | ACCOUNT_API 30 | double account_get_balance(const account_context_t *context); 31 | 32 | #ifdef __cplusplus 33 | } 34 | #endif 35 | 36 | #endif /* ACCOUNT_H_INCLUDED */ 37 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/solution/account/cffi_builder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from pathlib import Path 4 | from subprocess import check_output 5 | 6 | from cffi import FFI 7 | 8 | ffibuilder = FFI() 9 | 10 | definitions = ["-DACCOUNT_API=", "-DACCOUNT_NOINCLUDE"] 11 | header = Path(__file__).resolve().parent / "account.h" 12 | command = ["cc", "-E"] + definitions + [str(header)] 13 | interface = check_output(command).decode("utf-8") 14 | 15 | # remove possible \r characters on windows which 16 | # would confuse cdef 17 | _interface = [l.strip("\r") for l in interface.split("\n")] 18 | 19 | # cdef() expects a single string declaring the C types, functions and 20 | # globals needed to use the shared object. It must be in valid C syntax. 21 | ffibuilder.cdef("\n".join(_interface)) 22 | 23 | # set_source() gives the name of the python extension module to 24 | # produce, and some C source code as a string. This C code needs 25 | # to make the declared functions, types and globals available, 26 | # so it is often just the "#include". 27 | ffibuilder.set_source( 28 | "_pyaccount", 29 | """ 30 | #include "account.h" 31 | """, 32 | ) 33 | 34 | ffibuilder.emit_c_code("_pyaccount.c") 35 | -------------------------------------------------------------------------------- /content/code/day-2/28_fortran-cffi/solution/account/test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | sys.path.append(os.getenv('ACCOUNT_MODULE_PATH')) 4 | 5 | import account # isort: skip 6 | 7 | account1 = account.new() 8 | 9 | account.deposit(account1, 100.0) 10 | account.deposit(account1, 100.0) 11 | 12 | account2 = account.new() 13 | 14 | account.deposit(account2, 200.0) 15 | account.deposit(account2, 200.0) 16 | 17 | account.withdraw(account1, 50.0) 18 | 19 | assert account.get_balance(account1) == 150.0 20 | account.free(account1) 21 | 22 | assert account.get_balance(account2) == 400.0 23 | account.free(account2) 24 | -------------------------------------------------------------------------------- /content/code/day-2/29_visibility-levels/solution/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # define minimum cmake version 2 | cmake_minimum_required(VERSION 3.18) 3 | 4 | # project name and supported language 5 | project(bank LANGUAGES CXX) 6 | 7 | # require C++14 8 | set(CMAKE_CXX_STANDARD 14) 9 | set(CMAKE_CXX_EXTENSIONS OFF) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | # interface and sources 13 | add_subdirectory(account) 14 | 15 | add_executable(bank bank.cpp) 16 | 17 | target_link_libraries(bank 18 | PRIVATE 19 | account 20 | ) 21 | -------------------------------------------------------------------------------- /content/code/day-2/29_visibility-levels/solution/account/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(account SHARED "") 2 | 3 | target_sources(account 4 | PRIVATE 5 | account.cpp 6 | ) 7 | 8 | target_compile_options(account 9 | PUBLIC 10 | "-ffast-math" 11 | ) 12 | 13 | target_include_directories(account 14 | INTERFACE 15 | ${CMAKE_CURRENT_SOURCE_DIR} 16 | ) 17 | -------------------------------------------------------------------------------- /content/code/day-2/29_visibility-levels/solution/account/account.cpp: -------------------------------------------------------------------------------- 1 | #include "account.hpp" 2 | 3 | #include 4 | 5 | Account::Account() { 6 | balance = 0.0; 7 | is_initialized = true; 8 | } 9 | 10 | Account::~Account() { 11 | assert(is_initialized); 12 | is_initialized = false; 13 | } 14 | 15 | void Account::deposit(const double amount) { 16 | assert(is_initialized); 17 | balance += amount; 18 | } 19 | 20 | void Account::withdraw(const double amount) { 21 | assert(is_initialized); 22 | balance -= amount; 23 | } 24 | 25 | double Account::get_balance() const { 26 | assert(is_initialized); 27 | return balance; 28 | } 29 | -------------------------------------------------------------------------------- /content/code/day-2/29_visibility-levels/solution/account/account.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Account { 4 | public: 5 | Account(); 6 | ~Account(); 7 | 8 | void deposit(const double amount); 9 | void withdraw(const double amount); 10 | double get_balance() const; 11 | 12 | private: 13 | double balance; 14 | bool is_initialized; 15 | }; 16 | -------------------------------------------------------------------------------- /content/code/day-2/29_visibility-levels/solution/bank.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "account.hpp" 5 | 6 | int main() { 7 | auto acc = Account(); 8 | 9 | std::cout << "Depositing 100.0" << std::endl; 10 | acc.deposit(100.0); 11 | std::cout << " Balance: " << acc.get_balance() << std::endl; 12 | 13 | std::cout << "Withdrawing 50.0" << std::endl; 14 | acc.withdraw(50.0); 15 | std::cout << " Balance: " << acc.get_balance() << std::endl; 16 | 17 | std::cout << "Withdrawing 60.0" << std::endl; 18 | acc.withdraw(60.0); 19 | std::cout << " Balance: " << acc.get_balance() << std::endl; 20 | 21 | return EXIT_SUCCESS; 22 | } 23 | -------------------------------------------------------------------------------- /content/img/ENCCS.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/ENCCS.jpg -------------------------------------------------------------------------------- /content/img/binder_landing_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/binder_landing_page.png -------------------------------------------------------------------------------- /content/img/binder_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/binder_loading.png -------------------------------------------------------------------------------- /content/img/cmake-times.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/cmake-times.jpg -------------------------------------------------------------------------------- /content/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/favicon.ico -------------------------------------------------------------------------------- /content/img/launch_binder_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/launch_binder_button.png -------------------------------------------------------------------------------- /content/img/open_terminal_in_binder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/open_terminal_in_binder.png -------------------------------------------------------------------------------- /content/img/terminal_and_contents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ENCCS/cmake-workshop/f5a7b44d2514def33a2a164c024d6d9907a88ab6/content/img/terminal_and_contents.png -------------------------------------------------------------------------------- /content/quick-reference.rst: -------------------------------------------------------------------------------- 1 | Quick Reference 2 | --------------- 3 | -------------------------------------------------------------------------------- /content/zbibliography.rst: -------------------------------------------------------------------------------- 1 | Bibliography 2 | ------------ 3 | 4 | .. bibliography:: bibliography.bib 5 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: cmake-workshop 2 | channels: 3 | - conda-forge 4 | dependencies: 5 | - cffi 6 | - cmake >=3.18 7 | - compilers 8 | - graphviz 9 | - libblas 10 | - liblapack 11 | - libuuid 12 | - openmpi 13 | - ninja 14 | - pkg-config 15 | - python >=3.8 16 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx 2 | sphinx_rtd_theme 3 | sphinx_rtd_theme_ext_color_contrast 4 | sphinx-lesson ~= 0.8.4 5 | sphinxcontrib-bibtex 6 | --------------------------------------------------------------------------------