using
directivenamespace OpenMS
, namespace std
, or similar in .h
files may cause name clashes, therefore it is advised against.
-
-@warning Don't import complete namespaces to the scope into .cpp
files. Instead, introduce individual symbols to the scope where you need them. For example, write using std::vector;
instead of using namespace std;
. This immediately gives a hint to where the symbol is defined as well.
-
-UInt
vs Size
STL
types (especially vectors), assign the return value of a .size()
operation to the OpenMS type Size
, which is defined as follows:
-
-@code{.cpp}
-// OpenMS/include/CONCEPT/Types.h
-typedef size_t Size;
-@endcode
-
-Here is an example of how to correctly use Size
.
-
-@code{.cpp}
-std::vectorSize
. Even though UInt
and Size
are equivalent on prominent 32 bit systems, they are usually different types on 64 bit systems, where UInt
is 32 bit, whereas Size
is 64 bit depending on the platform. Using UInt
leads to warnings (at best) and may break your code.
-
-Size
is an unsigned type. If you need a signed type (e.g. when comparing length of vectors), use SignedSize
(also defined in types.h
)
-
-Use SignedSize
if you require loop variables with negative values. Here is an example:
-
-@code{.cpp}
-std::vectorGCC
to access common math functions like trunc()
, round()
, log2()
, etc. As this is not a C++ Standard requirement, Microsoft have decided to not include them. If GCC
is used, it will break the windows port of OpenMS.
-
-Instead, do the following to use these common math functions:
-ceil()
and floor()
To use these functions, use the following directive:
-@code{.cpp} -#include cmath -@endcode -Find information about math functions available at the cplusplus website or for VisualStudio specific problems: MSDN.
- -round()
OpenMS provides a Math::round()
function for convenience (see MATH/MISC/MathFunctions.h
).
isnan()
and isinf()
Use the boost
library. Include:
boost::math::isinf(myNumber)
and boost::math::isnan(myNumber)
.
-
-log()
Windows does not support log2()
; use log(x)/log(2)
instead.
int
, double
, float
, ....) all method arguments should be passed as non-mutable references.
-
-Return types of methods should be non-mutable references as well, where possible. Sometimes, references can't be used as the retuned value is constructed in the method. If the constructed type is large, save computation time with:
-
-@code{.cpp}
-//Bad idea
-LargeObject someFunction()
-{
- LargeObject tmp = ...
- return tmp;
-}
-//Better idea
-void someFunction(LargeObject& obj)
-{
- obj = ...
-}
-@endcode
-
-OPENMS_DLLAPI
?OPENMS_DLLAPI
is a preprocessor macro and ensures that Visual Studio exports this class into the DLL
when building the DLL
or references the DLL
when building an executable.
-
-The OPENMS_DLLAPI
macro is defined empty on other platforms, but it might still confuse the syntax parsing of the text editor or IDE. If you are using the Eclipse Platform, fix this at: Project > Properties > C/C++ Include Paths and Symbols.
-
-OPENMS_DLLAPI
OPENMS_DLLAPI
is also required for structs, global (including extern
) variables and global functions, as long as they are not templates. Never prefix templates with OPENMS_DLLAPI
. The only exception to this rule is when a template is fully specialized (i.e. it can be instantiated). Additionally, prefix nested public structs/classes with OPENMS_DLLAPI
, otherwise you cannot use them from outside the library.
-
-A prominent global function is "operator <<", which is overloaded quite often for OpenMS classes. Unless it is templatized, prefix it with OPENMS_DLLAPI
. If the operator is declared a friend of some class, also make sure the friend statement contains the OPENMS_DLLAPI
keyword. Otherwise, you will get inconsistent DLL-linkage. For example, use:
-
-@code{.cpp}
-// Adduct.h
-class OPENMS_DLLAPI Adduct
-{
- ...
- friend OPENMS_DLLAPI std::ostream& operator << (std::ostream& os, const Adduct& a);
- ...
-}
-// Adduct.C
-namespace OpenMS
-{
- OPENMS_DLLAPI std::ostream& operator << (std::ostream& os, const Adduct& a)
- {
- ...
- }
-}
-@endcode
-
-If you forget the OPENMS_DLLAPI
keyword, the DLL will have missing symbols and executables might not be able to link against the DLL. When compiled with gcc
you will get .. undefined reference to ..
errors.
-
-@section pointers_vs_references Pointers vs references
-
-Avoid using pointers. Pointers tend to cause segmentation faults. Try to use references instead.
-
-@section iterators Iterators
-
-In simple looping constructs, iterators are generally preferable to indexed access. Prefer ++i
to i++
, because the preincrement operator can save a copy constructor. Use const_iterators
where possible to help avoid unwanted side effects.
-
-@section includes Includes
-
-includes
in header files should be avoided and replaced by forward declarations. Unnecessary includes
cause longer compile times after changes in OpenMS header.
-
-Reasons for includes in header files are:
-T
(not T*
or T&
) the header has to be included.std::cout << "example" << std::endl;
forces the output buffer to be flushed, i.e. written to disk immediately, which is not ideal. Get used to writing code like std::cout << "example\n";
. Debugging output can be an exception, because the content of the stream buffer may be lost upon segfault etc..
-
-Write many digits to avoid unnecessary rounding errors. In particular, using standard output stream operators, i.e. << for doubles and floats should be avoided when full precision is required because by default, not all significant digits will be written. Before you start using os.precision(writtenDigits(FloatingPointType()));
and alike, it is strongly advised to convert to an OpenMS::String
, i.e. os << String(my_number)
because it's faster, and gives you all significant digits for each type (6 digits for float
, 15 for double
). Similarly, input stream operators are also slow, especially in VisualStudio, so switching to OpenMS::String::toDouble()
is advised for performance reasons. If you do not need all significant digits, simply invoke String(my_number, full_precision = false)
to get up to only three fractional digits for float
and double
types. For Integer
types, there is no problem with streams, but again: OpenMS::String(int i)
is faster. There is usually no heap allocation overhead for strings because of Small String Optimizations (SSO).
-
-*/
diff --git a/doc/doxygen/public/coding-conventions.doxygen b/doc/doxygen/public/developer_coding_conventions.doxygen
similarity index 96%
rename from doc/doxygen/public/coding-conventions.doxygen
rename to doc/doxygen/public/developer_coding_conventions.doxygen
index 3e0d8c20cab..929a5a4475e 100644
--- a/doc/doxygen/public/coding-conventions.doxygen
+++ b/doc/doxygen/public/developer_coding_conventions.doxygen
@@ -1,10 +1,12 @@
/**
- @page coding_conventions Coding Conventions
+ @page developer_coding_conventions Coding Conventions
Use the following code conventions when contributing to %OpenMS.
- %OpenMS uses coding conventions that are automatically checked using cpplint
(/src/tests/coding/cpplint.py
). You can find a configuration file for the CLion IDE
here. You can import it by selecting Preferences > Code Style > Manage.
+ %OpenMS uses coding conventions that are automatically checked using cpplint
(/src/tests/coding/cpplint.py
), when `ENABLE_STYLE_TESTING` flag is 'ON' during CMake.
+
+ When developing in an IDE which support [Clang format](https://clang.llvm.org/docs/ClangFormat.html) you can use the our style preset from the source tree `OpenMS/.clang-format`. For Clion, you can import it by selecting **Preferences** > **Code Style** > **Manage**. [VS2017 and later also support Clang format](https://devblogs.microsoft.com/cppblog/clangformat-support-in-visual-studio-2017-15-7-preview-1/) natively (press `Ctrl-K, Ctrl-D`).
@tableofcontents
@@ -53,8 +55,8 @@
@code{.cpp}
if (isValid(a))
- error = 0;
- return 0;
+ has_error = false;
+ return 0; // bug: will always return
@endcode
Thus, use braces around a block even for a single line.
@@ -501,11 +503,11 @@
@subsection examples Examples
- Instructive programming examples are provided in the doc/code_examples
directory
+ Instructive programming examples are provided in the doc/code_examples
directory. See @ref developer_tutorial.
@section testing Testing
- View the @subpage how_to_write_tests guidelines to learn how to write tests.
+ View the @subpage developer_how_to_write_tests guidelines to learn how to write tests.
@section revision_control Revision control
%OpenMS uses git to manage different versions of the source files. For easier identification of the responsible person each %OpenMS file contains the $Maintainer:$
string in the preamble.
diff --git a/doc/doxygen/public/developer_cpp_guide.doxygen b/doc/doxygen/public/developer_cpp_guide.doxygen
new file mode 100644
index 00000000000..e9888e9461d
--- /dev/null
+++ b/doc/doxygen/public/developer_cpp_guide.doxygen
@@ -0,0 +1,163 @@
+/**
+
+@page developer_cpp_guide C++ Guide
+
+The following page contains OpenMS-specific C++ guidelines, which are unrelated to @ref developer_coding_conventions.
+
+
+
+@section cpp_guide_dllapi What is `OPENMS_DLLAPI`?
+OPENMS_DLLAPI
is a preprocessor macro and ensures that the compiler, e.g. Visual Studio or g++, exports this class into the DLL
when building the DLL
or, in the other case, references the DLL
when building an executable.
+
+The OPENMS_DLLAPI
macro is defined in OpenMSConfig.h, which in turn is created at configure time (when CMake runs).
+
+**Details**: on MSVC, its either set to `__declspec(dllexport)` or `__declspec(dllimport)`, depending on who includes the header (within OpenMS library, or from outside, e.g. TOPP tools or class tests.).
+On g++/clang it's always `__attribute__((visibility("default")))`.
+
+
+
+@section cpp_guide_dllapi_when When to use `OPENMS_DLLAPI`?
+When you've written a new OpenMS class, which is not a template class, insert the macro into the header like this:
+
+@code{.cpp}
+class Myclass
+{ ...
+@endcode
+
+becomes:
+
+@code{.cpp}
+class OPENMS_DLLAPI Myclass
+{ ...
+@endcode
+
+It is enough to prefix the class with the macro. Do not prefix the members or member functions.
+
+OPENMS_DLLAPI
is also required for structs, global (including `extern`) variables and global functions, as long as they are not templates. Never prefix templates with `OPENMS_DLLAPI`. The only exception to this rule is when a template is fully specialized (i.e. it can be instantiated). Additionally, prefix nested public structs/classes with `OPENMS_DLLAPI`, otherwise you cannot use them from outside the library.
+
+A prominent global function is "operator <<", which is overloaded quite often for OpenMS classes. Unless it is templatized, prefix it with `OPENMS_DLLAPI`. If the operator is declared a friend of some class, also make sure the friend statement contains the `OPENMS_DLLAPI` keyword. Otherwise, you will get inconsistent DLL-linkage. For example, use:
+
+@code{.cpp}
+// Adduct.h
+class OPENMS_DLLAPI Adduct
+{
+ ...
+ friend OPENMS_DLLAPI std::ostream& operator<<(std::ostream& os, const Adduct& a);
+ ...
+}
+// Adduct.C
+namespace OpenMS
+{
+ OPENMS_DLLAPI std::ostream& operator<<(std::ostream& os, const Adduct& a)
+ {
+ ...
+ }
+}
+@endcode
+
+If you forget the `OPENMS_DLLAPI` keyword, the .dll/.so will have missing symbols and executables might not be able to link against it. When compiled with `g++` you will get .. undefined reference to ..
errors.
+
+
+
+
+
+@section cpp_guide_logging Logging
+To make direct output to `std::out` and `std::err` more consistent, %OpenMS provides several low-level macros:
+@code
+OPENMS_LOG_FATAL_ERROR,
+OPENMS_LOG_ERROR
+OPENMS_LOG_WARN,
+OPENMS_LOG_INFO and
+OPENMS_LOG_DEBUG
+@endcode
+which should be used instead of the less descriptive `std::out` and `std::err` streams.
+Furthermore, the %OpenMS loggers insert console coloring for their output and have a deduplication cache build in, which prevents repetitive outputs by aggregating and counting their occurence.
+See the OpenMS::LogStream class for details.
+
+In a similar vein: If you are writing an %OpenMS tool, you can also use the ProgressLogger to indicate how many percent of the processing has already been performed:
+stream_object << "example" << std::endl;
forces the output buffer to be flushed, i.e. written to disk/console immediately, which can be a big performance loss. Get used to writing code like stream_object << "example\n";
. Debugging output can be an exception, because the content of the stream buffer may be lost upon segfault etc..
+
+Write many digits to avoid unnecessary rounding errors. In particular, using standard output stream operators, i.e. << for doubles and floats should be avoided when full precision is required because by default, not all significant digits will be written. Before you start using os.precision(writtenDigits(FloatingPointType()));
and alike, it is strongly advised to convert to an OpenMS::String
, i.e. os << String(my_number)
because it's faster, and gives you all significant digits for each type (6 digits for float
, 15 for double
). Similarly, input stream operators are also slow, especially in VisualStudio, so switching to OpenMS::String::toDouble()
is advised for performance reasons. If you do not need all significant digits, simply invoke String(my_number, full_precision = false)
to get up to only three fractional digits for float
and double
types. For Integer
types, there is no problem with streams, but again: OpenMS::String(int i)
is faster. There is usually no heap allocation overhead for strings because of Small String Optimizations (SSO).
+
+
+
+@section cpp_guide_uint `UInt` vs. `Size`
+
+%OpenMS uses some custom type definitions for simple arithmetic types, such as `UInt` (shorthand for `unsigned int`).
+When working with STL
types (especially vectors), assign the return value of a .size()
operation to the %OpenMS type Size
, which is defined as follows:
+
+@code{.cpp}
+// OpenMS/include/CONCEPT/Types.h
+typedef size_t Size;
+@endcode
+
+Here is an example of how to correctly use Size
.
+
+@code{.cpp}
+void print(const std::vectorUInt
as a substitute for Size
. Even though UInt
and Size
are equivalent on prominent 32 bit systems, they are usually different types on 64 bit systems, where UInt
is 32 bit, whereas Size
is 64 bit depending on the platform. Using UInt
leads to warnings (at best) and may break your code.
+
+`Size` is an unsigned type. If you need a signed equivalent, use `SignedSize` (also defined in types.h
).
+
+
+
+@section cpp_guide_pointers_vs_references Pointers vs references
+
+Avoid using pointers. Pointers tend to cause segmentation faults. Try to use references instead.
+
+
+@section cpp_guide_includes Includes
+
+includes
in header files should be avoided and replaced by forward declarations. Unnecessary includes
cause longer compile times.
+
+Reasons for includes in header files are:
+T
(not T*
or T&
) the header has to be included.dumpbin /DEPENDENTS OpenMS.dll
.
+
+
@subsection how_to_get_a_list How to get a list of the symbols defined in a (shared) library or object file?
Linux: Use nm <library>
.
@@ -210,6 +212,39 @@
Use dumpbin on object files (.o) or (shared) library files (.lib) or the DLL itself e.g. dumpbin /EXPORTS OpenMS.dll
.
+
+
+ @subsection dev_faq_application_not_starting Why does my TOPP tool fail to start
+
+