Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 9b8bd8ea authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

Add as suggested by Vincent -j 1.

parent bdbbc0f0
Branches
No related tags found
1 merge request!108Notebook about dealing with compilation errors
%% Cell type:markdown id:0 tags:
# [Getting started in C++](./) - [Appendix](./0-main.ipynb) - [Dealing with compilation errors](./CompilationErrors.ipynb)
%% Cell type:markdown id:1 tags:
## Introduction
It is easy to be annoyed by the compilation process in C or C++: you write code, want to check how it goes, and that pesky compiler keeps preventing you to just do that by complaining about insignificant stuff as inadequate syntax, sometimes in a really confusing way (and it used to be much worse 20 years ago - compilers aim to be much more user-friendly now).
It is better though to adopt the opposite view: the compiler is not an opponent, but an _ally_ - and in the end you really benefit from identifying issues at compile time than at runtime.
The purpose of current notebook is to provide hints how to use to your own advantage the compiler and your build tool.
%% Cell type:markdown id:2 tags:
## Take error messages from top to bottom
%% Cell type:markdown id:3 tags:
When compiling even a single file (more on that below), the compiler may lay out plenty of compilation errors, even if most of the time they stop at some points (typically after around 20 errors have been printed).
That doesn't mean there are really 20 (or more) locations in your source file that needs to be fixed: sometimes the compiler can be very confused and isn't able to parse correctly the file.
This is especially true after very usual mistakes such as missing ')', '}' or ';'.
So what I (Sébastien) do is almost always begin at the top of the errors and see if solving this one explain the following errors or not.
I sometimes even redirect the output of the compilation into a file so that I can easily access the top. To my knowledge there's no clean way to do it more properly with the build tool directly; I would be delighted if someone proved me wrong on this one because the following sequence is not entirely satisfactory:
%% Cell type:markdown id:4 tags:
```shell
ninja 2>&1 | tee compilation_output.txt
ninja -j 1 2>&1 | tee compilation_output.txt
head -n 50 compilation_output.txt
```
%% Cell type:markdown id:5 tags:
## Master when (not to) use parallel build
(we'll come to the `-j 1` just below)
%% Cell type:markdown id:6 tags:
## Master when (not to) use parallel build
%% Cell type:markdown id:7 tags:
To leverage the multiple processors available in your computer, you should really take advantage of parallel build... (that we evoked briefly [here](http://localhost:8888/lab/tree/6-InRealEnvironment/1-SetUpEnvironment.ipynb#Build-system)) unless of course you have something better to do (courtesy [Xkcd](https://xkcd.com/303/))
%% Cell type:markdown id:7 tags:
%% Cell type:markdown id:8 tags:
![Xkcd](../Images/Xkcd-compiling.png)
%% Cell type:markdown id:8 tags:
%% Cell type:markdown id:9 tags:
It's especially useful when you modified an header file that is heavily used directly or indirectly in your program or your library - all files that depend on it will in this case be recompiled.
But why talk about it here, in a notebook about compilation errors?
The reason is that for compilation errors, I would recommend doing exactly the opposite: once you know something is amiss, you should really strive to concentrate on one error and fix it.
If you're using without much thoughts the output of a parallel build, you may end up providing a fix to a compilation error that is not correct, run a new compilation, and switch to an entirely other issue without realizing that your first fix doesn't work.
I (Sébastien) even go a step further: when I get an error message, I usually copy/paste the command line provided by my build tool (combo CMake / Ninja) until it compiles correctly. For instance if I get:
%% Cell type:markdown id:9 tags:
%% Cell type:markdown id:10 tags:
```shell
➜ ninja Sources/TestPetscMatrixOperations
[1/2] Building CXX object Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o
FAILED: Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o
/Users/sgilles/opt/clang_debug/Openmpi/bin/mpic++ -DDEBUG=1 -DMOREFEM_WITH_MUMPS -DMOREFEM_WITH_SLEPC -DMOREFEM_WITH_SUPERLU_DIST -DMOREFEM_WITH_UMFPACK -D_LIBCPP_DEBUG2=0 -I/Users/sgilles/Codes/MoReFEM/CoreLibrary/Sources -I/Users/sgilles/opt/clang_debug/Petsc/include -I/Users/sgilles/opt/clang_debug/Petsc/config_morefem/include -I/Users/sgilles/opt/clang_debug/Slepc/include -I/Users/sgilles/opt/clang_debug/Slepc/config_morefem/include -I/Users/sgilles/opt/clang_debug/Scotch/include_stub -I/Users/sgilles/opt/clang_debug/Scotch/include -I/Users/sgilles/opt/clang_debug/Lua/include -I/Users/sgilles/opt/clang_debug/Boost/include -I/Users/sgilles/opt/clang_debug/Xtensor/include -I/Users/sgilles/opt/clang_debug/Tclap/include -I/Users/sgilles/opt/clang_debug/Libmeshb/include -stdlib=libc++ -g -std=c++20 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk -fPIE -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-exit-time-destructors -Wno-global-constructors -Wno-documentation -Wno-documentation-unknown-command -Wno-undefined-func-template -Wno-c11-extensions -Wno-c++1z-extensions -Wno-used-but-marked-unused -Wno-unsafe-buffer-usage -fcolor-diagnostics -fdiagnostics-show-option -MD -MT Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o -MF Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o.d -o Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o -c /Users/sgilles/Codes/MoReFEM/CoreLibrary/Sources/Test/ThirdParty/PETSc/MatrixOperations/test.cpp
/Users/sgilles/Codes/MoReFEM/CoreLibrary/Sources/Test/ThirdParty/PETSc/MatrixOperations/test.cpp:96:20: error: no member named 'Fill' in 'MoReFEM::GlobalMatrix'
initial_matrix.Fill(1.);
~~~~~~~~~~~~~~ ^
1 error generated.
ninja: build stopped: subcommand failed.
```
%% Cell type:markdown id:10 tags:
%% Cell type:markdown id:11 tags:
I copy/paste the command helpfully provided by CMake and work on it until the issue is fixed (in the case above it wouldn't take long of course!)
%% Cell type:markdown id:11 tags:
%% Cell type:markdown id:12 tags:
```shell
/Users/sgilles/opt/clang_debug/Openmpi/bin/mpic++ -DDEBUG=1 -DMOREFEM_WITH_MUMPS -DMOREFEM_WITH_SLEPC -DMOREFEM_WITH_SUPERLU_DIST -DMOREFEM_WITH_UMFPACK -D_LIBCPP_DEBUG2=0 -I/Users/sgilles/Codes/MoReFEM/CoreLibrary/Sources -I/Users/sgilles/opt/clang_debug/Petsc/include -I/Users/sgilles/opt/clang_debug/Petsc/config_morefem/include -I/Users/sgilles/opt/clang_debug/Slepc/include -I/Users/sgilles/opt/clang_debug/Slepc/config_morefem/include -I/Users/sgilles/opt/clang_debug/Scotch/include_stub -I/Users/sgilles/opt/clang_debug/Scotch/include -I/Users/sgilles/opt/clang_debug/Lua/include -I/Users/sgilles/opt/clang_debug/Boost/include -I/Users/sgilles/opt/clang_debug/Xtensor/include -I/Users/sgilles/opt/clang_debug/Tclap/include -I/Users/sgilles/opt/clang_debug/Libmeshb/include -stdlib=libc++ -g -std=c++20 -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.2.sdk -fPIE -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-exit-time-destructors -Wno-global-constructors -Wno-documentation -Wno-documentation-unknown-command -Wno-undefined-func-template -Wno-c11-extensions -Wno-c++1z-extensions -Wno-used-but-marked-unused -Wno-unsafe-buffer-usage -fcolor-diagnostics -fdiagnostics-show-option -MD -MT Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o -MF Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o.d -o Sources/CMakeFiles/TestPetscMatrixOperations.dir/Test/ThirdParty/PETSc/MatrixOperations/test.cpp.o -c /Users/sgilles/Codes/MoReFEM/CoreLibrary/Sources/Test/ThirdParty/PETSc/MatrixOperations/test.cpp
```
%% Cell type:markdown id:12 tags:
%% Cell type:markdown id:13 tags:
### Know your build tool
When doing refactoring, you might want to know exactly how many files are impacted and don't compile. Usually a build tool will stop as soon as there is a file that chokes (or in case of a parallel build until all the processors meet such a file).
However, there are usually options to tell to compile all that can be compiled; it is for instance `ninja -k 0` for `ninja`.
%% Cell type:markdown id:13 tags:
%% Cell type:markdown id:14 tags:
## Read carefully the message
As said in the introduction, compilers are now much more helpful now that what they used to be (see for instance in the example above: it even tries to tell me where exactly in the line the error occurs).
Most of the error messages are now clear enough; when they're not you may find information on the Web as the question has surely be posted somewhere (StackOverflow or similar sites).
c++filt (that we mentioned [here](../6-InRealEnvironment/3-Compilers.ipynb#c++filt)) may be of help if the mangling makes the name of your function / class / whatever too difficult to read.
%% Cell type:markdown id:14 tags:
%% Cell type:markdown id:15 tags:
## Don't neglect warnings
When the compilation fails, you may get a jungle of error and warning messages, with an emphasis on errors (that are typically in deep red, whereas warnings are in yellow or purple).
You should however at least read the warning - it might point the very reason for which something is amiss in your code.
Personally I handle them almost exactly the same way as error - it's only when I know for sure that the warning bears no relationship to the following error message that I put it aside.
%% Cell type:markdown id:15 tags:
%% Cell type:markdown id:16 tags:
## Make sure you're correctly identifying which overload / constructor / etc... is involved
C++ gives you a lot of liberties with naming: same name might be used with a different signature (function overload or multiple constructors for a class for instance) or used in a different namespace.
Make sure you connect the dots well!
%% Cell type:markdown id:16 tags:
%% Cell type:markdown id:17 tags:
## Include-related potential issues
### Missing include
Sometimes a compilation error might just be due to a missing include!
If the compiler complains about an unknown function, it might just be that the specific source file in which it happens doesn't provide properly the declaration.
### Circular dependency
This is one of the worst compilation you might get, as the compiler won't be able to tell you clearly what happens.
If the compiler complains that it doesn't know about a specific function (or class or method) whereas you're absolutely positive that it is already provided and that you didn't fall into the trap mentioned [just above](http://localhost:8888/lab/tree/7-Appendix/CompilationErrors.ipynb#Make-sure-you're-correctly-identifying-which-overload-/-constructor-/-etc...-is-involved), you might be in a case of circular dependency.
This happens when a file `A.hpp` is included in `B.hpp`, which itself is included in `A.hpp`. Said like that it seems trivial and easy to spot, but in a real code it is often definitely not - as it might be for instance that `B.hpp` includes other headers, which themselves include others, one of which at some point include `A.hpp`.
The way to avoid it is to carefully think your architecture: if there is a clear hierarchy between your components, you should be able to avoid it most of the time.
You should also strive to limit to the minimum the includes to provide in other header files; use [forward declaration](http://localhost:8888/lab/tree/6-InRealEnvironment/2-FileStructure.ipynb#Forward-declaration) when you can, and don't provide includes that are needed only for implementation if said implementation is in a compiled file (of course for `inline` functions `template` classes and functions you don't have the choice). Doing so will also help you limit compilation time anyway.
### Duplicate header guards
Another typical issue is if you provide the same [header guard](http://localhost:8888/lab/tree/6-InRealEnvironment/2-FileStructure.ipynb#Forward-declaration) in two different files.
In this case, one of them will be simply ignored, and its content will probably be sorely missing somewhere along the line in the compilation process.
To avoid this, you should either use `#pragma once` instead, or automate one way or the other the header guard names in the file to ensure unicity.
%% Cell type:markdown id:17 tags:
%% Cell type:markdown id:18 tags:
## Template keyword
%% Cell type:markdown id:18 tags:
%% Cell type:markdown id:19 tags:
We dedicated a [notebook](../4-Templates/3-Syntax.ipynb) to the specific syntax that might be required to help the compiler understand what is the intention with some specific template tricks.
In both the cases we covered in this notebook, we rejoiced that the compiler was rather helpful if you forgot to use properly one of the expected keyword... but for the `template` keyword (described [here](../4-Templates/3-Syntax.ipynb#Mandatory-template-keyword)) it is fairly recent (around 2022!) - so if you're using a not so recent compiler and get an error message about an unknown method whereas
- This method do exist
- This method is properly declared at to calling site (it's not a missing include)
- This method is a template method within a template class
then you should have a look at the explanation in the notebook about the `template` keyword.
%% Cell type:markdown id:19 tags:
%% Cell type:markdown id:20 tags:
## Help yourself making the compiler error messages clearer!
Recent versions of C++ have provided many great tools to help you specify at compile time that a condition must be met:
- `static_assert` (since C++ 11)
- `concept` (since C++ 20)
To which you may also add nifty stuff not directly in the language or STL but that may be added easily such as strong types (here is a [series of FluentCpp posts](https://www.fluentcpp.com/2016/12/05/named-constructors/) explaining the underlying idea; an implementation is provided [there](https://github.com/joboccara/NamedType) but it's easy to write your own implementation tailored for your needs when you read the series).
You should really consider using them, especially if you're writing a library, because it might really save a lot of time for the user of the library if a clear message explains exactly how the code didn't match the expectations of the library.
%% Cell type:markdown id:20 tags:
%% Cell type:markdown id:21 tags:
[© Copyright](../COPYRIGHT.md)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment