Naming convention for components and namespaces in cmake - cmake

In Short:
Is there any preferred naming convention for cmake library targets - in particular when using namespaces?
Note:
Unless there is really an objective reason for it, I'm not asking about personal preferences, but whether there is either an "official" (e.g. recommended by kitware) or established (which might deviate) convention.
Details:
Lets say I have a library/framework foo which has the individual components bar and baz. So far, my naming convention looks like this:
add_library(foo-bar src1.cpp, scr2.cpp)
add_library(foo-baz src3.cpp, src4.cpp)
Now I want to add alias targets using the namespace (::) convention. E.g.
add_library(Foo::Bar ALIAS foo-bar)
add_library(Foo::Baz ALIAS foo-baz)
(Of course the question also extends to export sets, but I didn't want to complicate the question)
What I couldn't really find out however, is if there is a preferred or even official naming convention for those targets.
Things I've seen:
Namespace part:
some projects seem to capitalize the first letter, some not (the former seems to be more common)
Component part:
in some projects, the component name is the same as the binary name
with or without the "lib" prefix (libfoo-bar vs foo-bar)
with or without the namespace (foo-bar vs bar)
some projects capitalize the first letter
some projects use CamelCase some snake_case, even if the binaries or project names don't follow those conventions.
I guess the main problem is that there is no naming convention for libraries in general so that makes it hard to come up with a naming convention in CMake, but at least the capitilization for the first letter of the namespace and the component seem to be pretty common, so I was wondering if there is some guideline I should follow for future projects.

The cmake-developer documentation gives the following advice on namespaces:
When providing imported targets, these should be namespaced (hence the Foo:: prefix); CMake will recognize that values passed to target_link_libraries() that contain :: in their name are supposed to be imported targets (rather than just library names), and will produce appropriate diagnostic messages if that target does not exist (see policy CMP0028).
And the CMP0028 policy documentation says on the "common pattern" in the use of namespaces:
The use of double-colons is a common pattern used to namespace IMPORTED targets and ALIAS targets. When computing the link dependencies of a target, the name of each dependency could either be a target, or a file on disk. Previously, if a target was not found with a matching name, the name was considered to refer to a file on disk. This can lead to confusing error messages if there is a typo in what should be a target name.
And no, there are no CMake specific convention for the naming of library targets. But since the name is taken by default as the target's output name:
I prefer to take the same name for the targets as for my source code directory
And add no lib prefix, since this is automatically added by CMake depending on the platform you are compiling your project with
From the CMake Tutorial
The most official source you could get is probably an extract from the "Mastering CMake" book written by Ken Martin and Bill Hoffman from Kitware.
The tutorials from the book all use CamelCase and no namespaces for component/target names.
References
What is the naming convention for CMake scripts?
cmake usefulness of aliases

Related

How can I avoid clashes with targets "imported" with FetchContent_MakeAvailable?

Suppose I'm writing an app, and managing its build with CMake; and I also want to use a library, mylib, via the FetchContent mechanism.
Now, my own CMakeLists.txt defines a bunch of targets, and so does mylib's CMakeLists.txt. If I were to install mylib, then find_package(mylib), I would only get its exported targets, and even those would be prefixed with mylib:: (customarily, at least). But with FetchContent, both my app's and mylib's (internal and export-intended) targets are in the "global namespace", and may clash.
So, what can I do to separate those targets - other than meticulously name all of my own app's targets defensively?
I would really like it if it were possible to somehow "shove" all the mylib targets into a namespace of my choice.
Note: Relates to: How to avoid namespace collision when using CMake FetchContent?
In the current CMake (<=3.24) world, there are no features for adjusting the names of the targets in other black-box projects, whether included via find_package, add_subdirectory, or FetchContent. Thus, for now, it is incumbent on you to avoid name-clashes in targets, install components, test names, and anywhere else this could be a problem.
Craig Scott says as much in his (very good) talk at CppCon 2019, see here: https://youtu.be/m0DwB4OvDXk?t=2186
The convention he proposes is to use names that are prefixed with SomeProj_. He doesn't suggest to literally use ${PROJECT_NAME}_, and I wouldn't either, because doing so makes the code harder to read and grep (which is extremely useful for understanding a 3rd-party build).
To be a good add_subdirectory or FetchContent citizen, however, it is not enough to simply namespace your targets as SomeProj_Target; you must also provide an ALIAS target SomeProj::Target. There are a few reasons for this:
Your imported targets from find_package will almost certainly be named SomeProj::Target. It should be possible for consumers of your library to switch between FetchContent and find_package easily, without changing other parts of their code. The ALIAS target lets you expose the same interface in both cases. This will become especially pressing when CMake 3.24 lands with its new find_package-to-FetchContent redirection features.
CMake's target_link_libraries function treats names that contain :: as target names always and will throw configure-time error if the target does not exist. Without the ::, it will be treated as a target preferentially, but will turn into a linker flag if the target doesn't exist. Thus, it is preferable to link to targets with :: in their names.
Yet, only IMPORTED and ALIAS targets may have :: in their names.
Points (2) and (3) are good enough for me to define aliases.
Unfortunately, many (most?) CMake builds are not good FetchContent citizens and will flaunt this convention. Following this convention yourself reduces the chance of integration issues between your project and any other, but obviously does nothing to prevent issues between two third party projects that might define conflicting targets. In these cases, you're just out of luck.
An example of defining a library called Target that will play nice with FetchContent:
add_library(SomeProj_Target ${sources})
add_library(SomeProj::Target ALIAS SomeProj_Target)
set_target_properties(
SomeProj_Target
PROPERTIES
EXPORT_NAME Target
OUTPUT_NAME Target # optional: makes the file libTarget.so on disk
)
install(TARGETS SomeProj_Target EXPORT SomeProj_Targets)
install(EXPORT SomeProj_Targets NAMESPACE SomeProj::)
For a more complete example that plays nice with install components, include paths, and dual shared/static import, see my blog post.
See these upstream issues to track the progress/discussion of these problems.
#22687 Project-level namespaces
#16414 Namespace support for target names in nested projects
As #AlexReinking , and, in fact, Craig Scott, suggest - there's no decent current solution.
You can follow the following CMake issues through which the solution will likely be achieved:
#22687 Project-level namespaces (more current)
#16414 Namespace support for target names in nested projects (longer discussion which influenced the above, recommended reading)

Nested library namespace in CMake

When I see CMake libraries with namespaces they are always in the form
Parent::Component.
If I have a sufficiently large library, there may be subsections of that library that have components. I am wondering if it is possible/appropriate to do something like ParentProject::Subgouping::SpecificComponent or for a more real world example Raytracing::Math::Utils.
In short, can I use multiple namespaces in a CMake library name? If it is possible, is it a good idea?
In short, can I use multiple namespaces in a CMake library name?
Yes. A colon (:) is just like any other character in a CMake target name. However, the target_link_libraries command will interpret any argument containing :: in its name as a proper CMake target, rather than as a potential system library. So if you mis-type a target name or it otherwise doesn't exist, you'll get a useful error at configure time, rather than a broken build.
Having multiple instances of :: in the name behaves the same as having just one.
If it is possible, is it a good idea?
It's about as good an idea as nested namespaces are in C++. If it makes sense, do it. The only minor difference is that CMake has no using namespace equivalent, so they're slightly less convenient to type.
In several of my projects, I use a namespace like Project::Tools:: to hold any build-time tools (like custom code generators) that need to be built separately for the sake of cross-compilation (when CMAKE_CROSSCOMPILING_EMULATOR is not an option).

What's the idiomatic way to compile the same file twice, with different languages?

I have a source file which is valid in (at least) two languages. Say, C and C++ or C and CUDA.
I want to compile this file in both languages, each time into a different library. What's the idiomatic way of doing this in recent versions of CMake?
Notes:
If the specific version of CMake matters, please specify which minimum version I would need.
Related: How can I configure cmake to compile a file twice with two different compilers?
This elaborates on #KamilCuk's suggestion in a comment on the OP, written before I noticed the comment.
The LANGUAGE property is set on the source file itself, which is the core of your question. The documentation for this property describes it being visible in the scope of the directory where it is set. That means that one way to have different languages is to set the property in two different directories. For example:
src/
CMakeLists.txt
common/
main.c
app1/
CMakeLists.txt
app2/
CMakeLists.txt
src/CMakeLists.txt:
add_subdirectory(app1)
add_subdirectory(app2)
app1/CMakeLists.txt:
set_property(SOURCE ../common/main.c PROPERTY LANGUAGE CXX)
add_executable(app1 ../common/main.c)
app2/CMakeLists.txt:
set_property(SOURCE ../common/main.c PROPERTY LANGUAGE C)
add_executable(app2 ../common/main.c)
This will build main.c into two different targets, with two different LANGUAGE settings.
The docs also hint at being able to set the property explicitly against other directory scopes including binary directories. I was hoping this would help make the job simpler, but I can't get it to work.
Since, indeed, LANGUAGE is a per-file property, I believe what should happen - and would allow for a proper idiom here - is to have a binary relation of language-to-use for pairs of (target, source file).
I've suggested this to KitWare in an issue report (gitlab.kitware.com).

where is the list of names that cmake reserves?

Everything is in the title, but for more context informations:
I am creating a library, where all components are independent (it's only because it's easier to manage 1 git repo, really).
In that library's root folder, I have 1 sub-folder for each part of the library's components, with exactly 3 "interesting folders" (src,tests,include/components_name). I have hardcoded those folders in a foreach loop so that all actions will be done for all modules by default.
The problem seems to be that, one of the modules is named "option_parser" which is, indeed, relatively generic, and also seems to be "reserved" by cmake, and same for everything derived from it. I've tried "option_parser_test", "option_parser_tests", and other random names based on "option_parser_" root.
So, here is my question: where I can learn how to avoid names that cmake reserves?
And how can I affect them anyway to my binaries (because, I feel like it's stupid to change a project's name because of a build system. Might be a strong enough reason to switch it.)
It's really quite simple. Use these three commands to see all reserved words:
cmake --help-command-list
cmake --help-variable-list
cmake --help-property-list
The answer of Cinder Biscuits above should probably already help you.
Additionally, you should probably read CMake's own documentation regarding the CMake language and in particular the note in the "Variables" section:
Note: CMake reserves identifiers that:
begin with CMAKE_ (upper-, lower-, or mixed-case), or
begin with _CMAKE_ (upper-, lower-, or mixed-case), or
begin with _ followed by the name of any CMake Command.

What is proper naming convention for MSVC dlls, static libraries and import libraries

What is standard or "most-popular" naming convention for MSVC library builds.
For example, for following platforms library foo has these conventions:
Linux/gcc:
shared: libfoo.so
import: ---
static: libfoo.a
Cygwin/gcc:
shared: cygfoo.dll
import: libfoo.dll.a
static: libfoo.a
Windows/MinGW:
shared: libfoo.dll
import: libfoo.dll.a
static: libfoo.a
What should be used for MSVC buidls? As far as I know, usually names are foo.dll and foo.lib, but how do you usually distinguish between import library and static one?
Note: I ask because CMake creates quite unpleasant collision between them naming both import and static library as foo.lib. See bug report. The answer would
help me to convince the developers to fix this bug.
You distinguish between a library and a .dll by the extension. But you distinguish between a import library and a static library by the filename, not the extension.
There will be no case where an import library exists for a set of code that was built to be a static library, or where a static library exists for a dll. These are two different things.
There is no single MSVC standard filename convention. As a rule, a library name that ends in "D" is often a debug build of library code, msvcrtd.dll vs msvcrt.dll but other than that, there are no standards.
As mentioned by others, there are no standards, but there are popular conventions. I'm unsure how to unambiguously judge what is the most popular convention. In addition the nomenclature for static vs. import libraries, which you asked about, there is also an analogous distinction between the naming of Release libraries vs. Debug libraries, especially on Windows.
Both cases (i.e. static vs. import, and debug vs. release) can be handled in one of two ways: different names, or different directory locations. I usually choose to use different names, because I feel it minimizes the chance of mistaking the library type later, especially after installation or other file moving activities.
I usually use foo.dll and foo.lib for the shared library on Windows, and foo_static.lib for the static library, when I wish to have both shared and static versions. I have seen others use this convention, so it might be the "most popular".
So I would recommend the following addition to your table:
Windows/MSVC:
shared: foo.dll
import: foo.lib
static: foo_static.lib
Then in cmake, you could either
add_library(foo_static STATIC foo.cpp)
or
add_library(FooStatic STATIC foo.cpp)
set_target_properties(FooStatic PROPERTIES OUTPUT_NAME "foo_static")
if for some reason you don't wish to use "foo_static" as the symbolic library name.
There is no standard naming convention for libraries. Traditional library names are prefixed with lib. Many linkers have options to prepend lib to a library name on the command line.
The static and dynamic libraries are usually identified by their file extension; although this is not required. So libmath.a would be a static library whereas libmath.so or libmath.dll would be a dynamic library.
A common naming convention is to append the category of the library to the name. For example, a debug static math library would be 'libmathd.a' or in Windows, 'lib_math_debug'. Some shops also add Unicode as a filename attribute.
If you want, you can append _msvc to the library name to indicate the library requires or was created by MSVC (to differentiate from GCC and other tools). A popular convention when working with multiple platforms, is to place the objects and libraries in platform specific folders. For example a ./linux/ folder would contain objects and libraries for Linux and similarly ./msw/ for Microsoft Windows platform.
This is a style issue. Style issues are often treated like religious issues: none of them are wrong, there is no universal style, and they are an individual preference. What ever system you choose, just be consistent.
As far as I know, there's no real 'standard', at least no standard most software would conform to.
My convention is to name my dynamic and static .lib equally, but place them in different directories if a project happens to support both static and dynamic linkage. For example:
foo-static
foo.lib
foo
foo.lib
foo.dll
The library to link against depends on the choice of the library directories, so it's almost totally decoupled from the rest of the build process (it won't appear in-source if you use MSVC's #pragma comment(lib,"foo.lib") facility, and it doesn't appear in the list of import libraries for the linker).
I've seen this quite a few times. Also, I think that MSVC/Windows based projects tend to stick more often with a single, official linkage type - either static, or dynamic. But that's just my personal observation.
In short:
Windows/MSVC
shared: foo.dll
import: foo.lib
static: foo.lib
You should be able to use this directory-based pattern with CMAKE (never used it). Also, I don't think it's a 'bug'. It's merely lack of standardization. CMAKE does (imho) the right thing not to establish a pseudo-standard if everyone likes it differently.
As the others have said, there is no single standard to file naming on windows.
For our complete product base which covers 100's of exes, dlls, and static libs we have used the following successfully for many years now and it has saved a lot of confusion. Its basically a mixing of several methods I've seen used throughout the years.
In a nutshell all our files of both a prefix and suffix (not including the extension itself). They all start with "om" (based on our company name), and then have a 1 or 2 character combination that roughly identifies the area of code.
The suffix explains what type of built-file they are and includes up to three letters used in combination depending on the build which includes Unicode, Static, Debug (Dll builds are the default and have no explicit suffix identifier). When we started this system Unicode was not so prevalent and we had to support both Unicode and Non-unicode builds (pre Windows 2000 os), now everything is exclusively built unicode but we still use the same nomenclature.
So a typical .lib "set" of files might look like
omfThreadud.lib (Unicode/Debug/Dll)
omfThreadusd.lib (Unicode/Static/Debug)
omfThreadu.lib (Unicode/Release/Dll)
omfThreadus.lib (Unicode/static)
All files are built-in into a common bin folder, which eliminates a lot of dll-hell issues for developers and also makes it simpler to adjust compiler/linker settings - they all point to the same location using relative paths and there is never any need for manual (or automatic) copying of the libraries a project needs. Having these suffixes also eliminates any confusion as to what type of file you may have, and guarantees you can't have a mixed scenario where you put down the debug dll on a release kit or vice-versa. All exes also use a similar suffix (Unicode/Debug) and build into the same bin folder.
There is likewise one single "include" folder, each library has one header file in the include folder that matches the name of the library/dll (for example omfthread.h) That file itself #includes all the other items that are exposed by that library. This keeps its simpler if you want functionality that is in foo.dll you just #include "foo.h"; our libraries are highly segmented by areas of functionality - effectively we don't have any "swiss-army knife" dlls so including the libraries entire functionality makes sense. (Each of these headers also include other prerequisite headers whether they be our internal libraries or other vendor SDKs)
Each of these include files internally uses macros that use #pramga's to add the appropriate library name to the linker line so individual projects don't need to be concerned with that. Most of of our libraries can be built statically or as a DLL and #define OM_LINK_STATIC (if defined) is used to determine which the individual project wants (we usually use the DLLs but in some cases static libraries built-in into the .exe make more sense for deployment or other reasons)
#if defined(OM_LINK_STATIC)
#pragma comment (lib, OMLIBNAMESTATIC("OMFTHREAD"))
#else
#pragma comment (lib, OMLIBNAME("OMFTHREAD"))
#endif
These macros (OMLIBNAMESTATIC & OMLIBNAME) use _DEBUG determine what type of build it is and generate the proper library name to add to the linker line.
We use a common define in the static & dll versions of a library to control proper exporting of the class/functions in dll builds. Each class or function exported from the library is decorated with this macro (the name of which matches the base name for the library, though that is largely unimportant)
class OMUTHREAD_DECLARE CThread : public CThreadBase
In the DLL version of the project settings we define OMFTHREAD_DECLARE=__declspec(dllexport), in the static library version of the library we define OMFTHREAD_DECLARE as empty.
In the libraries header file we define it based on how the client is trying to link to it
#if defined(OM_LINK_STATIC)
#define OMFTHREAD_DECLARE
#else
#define OMFTHREAD_DECLARE __declspec(dllimport)
#endif
A typical project that wants to use one of our internal libraries would just add the appropriate include to their stdafx.h (typically) and it just works, if they need to link against the static version they just add OM_LINK_STATIC to their compiler settings (or define it in the stdafx.h) and it again it just works.
As far as I know there still aren't any conventions with regards to this. Here's an example of how I do it:
{Project}{SubModule}{Platform}{Architecture}{CompilerRuntime}_{BuildType}.lib/dll
The full filename shall be lowercase only and shall only contain alphanumerics with predesignated underscores. The submodule field, including its leading underscore, is optional.
Project: holds project name/identifier. Preferably as short as possible. ie "dna"
SubModule: optional. holds module name. Preferably as short as possible. ie "dna_audio"
Platform: identifies the platform the binary is compiled for. ie "win32" (Windows), "winrt", "xbox", "android".
Architecture: describes the architecture the binary is compiled for. ie "x86", "x64", "arm". There where architecture names are equal for various bitnesses use its name followed by the bitness. ie. "name16", "name32", "name64"
CompilerRuntime: optional. Not all binaries link to a compiler runtime, but if they do, it's included here. ie "vc90" (Visual Studio 2008), "gcc". Where applicable apartment can be included ie "vc90mt"
BuildType: optional. This can hold letters (in any order desired), each which tell something about the build-specifics. d=debug (omitted if release) t=static (omitted if dynamic) a=ansi (omitted if unicode)
Examples (assuming a project named "DNA"):
dna_win32_x86_vc90.lib/dll
dna_win32_x64_vc90_d.lib/dll
dna_win32_x86_vc90_sd.lib
dna_audio_win32_x64_vc90.lib/dll
dna_audio_winrt_x64_vc110.lib/dll