CMakeTutorias: target_compile_definitions(...) usage - c++

I have been following the CMakeTutorials and I have a question at Step10:
In this step, the use of target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
is introduced.
So first question: What exactly are compile_definitions?
Second question: In the top level CMakeLists.txt, before the changes of Step10, there is this command: option(USE_MYMATH "Use tutorial provided math implementation" ON). With this command, I understand that a variable USE_MYMATH is set to ON, and this variable is used both in the CMakeLists.txt (to choose if the tutorial library will be added to the build) and to the source code (tutorial.cxx) by the precompiler.
What the changes of Step10 bring is that, the USE_MYMATH variable is no longer used for that, but it is now created by the same command (option(USE_MYMATH "Use tutorial provided math implementation" ON)) in the CMakeLists of the custom MathFunctions library. What I do not understand is why target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") is also introduced.
Based on what I understood before Step10, the option() command should set the variable USE_MYMATH, and can be used afterwards both in the CMakeLists and in the source code by the precompiler. However, if in Step10 I do not include target_compile_definitions, then the source code of the library handles the source code as undefined. Why is that?

Related

CMake non-configurable option

In CMake, how can I define an option that is not configurable by the user, but automatically calculated?
I would like to do the following:
if (FOO AND NOT BAR)
option(BOO "Foo and not bar" ON)
endif()
And then I can use BOO in different CMake files:
if (BOO)
# do something
endif()
And also in sources:
#ifdef BOO
// do something
#endif
So BOO behaves like a regular option, but is automatically calculated and not configurable by user running cmake.
EDIT: I now realize that options are not implicitly available in sources, but need to be defined explicitly with target_add_definitions or other means. So now it becomes obvious that the solution is to define BOO as a CMake variable, rather than an option.
Your "non-user-configurable" option sounds like a variable, which you can create like:
if(FOO AND NOT BAR)
set(BOO TRUE)
else()
set(BOO FALSE)
endif()
To use this variable in C++ code, you need to tell CMake to create a C++ file which defines this information. Take a look at CMake's configure_file function. Here's the official documentation, and here's part of the official CMake tutorial which walks through a simple usage of this function. I would type out some example code, but it would be a lot of boilerplate, and the linked documents do the job and should be better at answering your questions.
There is an alternative to configure_file: using target_compile_definitions. The tradeoff to make is between simplicity of implementation and build times. If the value of a compile definitions changes upon reconfiguration, then CMake has to assume that every source file of the target needs to be recompiled, since it has no information about how that definition is being used (ie. target_compile_definitions is easy to implement, but can lead to much slower build times in specific scenarios). When you use configure_file, only the files that include the file that defines those definitions need to be recompiled. There's also potentially an argumen to be made about "readability": if your target gets installed, it's easier for someone reading the installed headers to find the definition versus having to read generated CMake files to find it.
This could be done using a normal variable, but in some scenarios this information will not be available everywhere, e.g. if the subdirectory structure created by add_subdirectory does not ensure the information is required only in the CMakeLists.txt file where the info is introduced or in one of it's descendant directories.
In this case you should be using a cache variable with type internal INTERNAL. This has the added benefit of allowing you to persist the info for use during reconfiguration. You could also use FORCE to overwrite the value of any cache variable.
Example
if (... BOO not yet set properly ...)
set(BOO_VALUE ...)
set(BOO ${BOO_VALUE} CACHE INTERNAL "") # internal implies FORCE
endif()
Note that this won't make the preprocessor define available. You still need to use something like
target_compile_definitions(mytarget PRIVATE "BOO=${BOO}")
You can just use variable with set(BOO <what you want>).
You can find the documentation here: https://cmake.org/cmake/help/latest/command/set.html
But there is no option that will restrict the value of your variable for an internal settings. Only you.

How can I get the C++ source code of a package on CRAN?

I am interested in the source code of the package https://rdrr.io/cran/fclust/, particularly the functions RI.F and ARI.F, but could only find the R implementations
https://rdrr.io/cran/fclust/src/R/RI.F.R
https://rdrr.io/cran/fclust/src/R/ARI.F.R
which are just link to the C++ code. Where is the source code of the C++ parts of a package usually available? Where in this case?
I am not sure if the package is Open Source to be honest and I am not sure if there is a place where the source code is "usually available".
I explain how to do it for fclust, but instead of just providing a link, I show the path to get there in such a way that it should be reproducible for many other packages at CRAN.
When you go to https://rdrr.io/cran/fclust/ then you see the table entry "Package repository" and behind it a link called "View on CRAN". When you go there and look underneath "Downloads:" you will see a link behind "Package source:". The source code is in the ".tar.gz".
Next, you have to look into the R-code and will see that the function partition_comp is called. You can also see it listed in https://rdrr.io/cran/fclust/f/ as src/partition_comp.cpp. So go into the ".tar.gz"-file and look for that file. It will contain the C++ source code.

Use autotools installation prefix

I am writing a C++ program using gtkmm as the window library and autotools as my build system. In my Makefile.am, I install the icon as follows:
icondir = $(datadir)/icons/hicolor/scalable/apps
icon_DATA = $(top_srcdir)/appname.svg
EDIT: changed from prefix to datadir
This results in appname.svg being copied to $(datadir)/icons/hicolor/scalable/apps when the program is installed. In my C++ code, I would like to access the icon at runtime for a window decoration:
string iconPath = DATADIR + "/icons/hicolor/scalable/apps/appname.svg";
// do stuff with the icon
I am unsure how to go about obtaining DATADIR for this purpose. I could use relative paths, but then moving the binary would break the icon, which seems evident of hackery. I figure that there should be a special way to handle icons separate from general data, since people can install 3rd party icon packs. So, I have two questions:
What is the standard way of installing and using icons with autotools/C++/gtkmm?
Edit: gtkmm has an IconTheme class that is the standard way to use icons in gtkmm. It appears that I add_resource_path() (for which I still need the installation prefix), and then I can use the library to obtain the icon by name.
What is the general method with autotools/C++ to access the autotools installation prefix?
To convey data determined by configure to your source files, the primary methods available are to write them in a header that your sources #include or to define them as macros on the compiler command line. These are handled most conveniently via the AC_DEFINE Autoconf macro. Under some circumstances, you might also consider converting source files to templates for configure to process, but except inasmuch as Autoconf itself uses an internal version of that technique to build config.h (when that is requested), I wouldn't normally recommend it.
HOWEVER, the installation prefix and other installation directories are special cases. They are not finally set until you actually run make. Even if you set them via the configure's command-line options, you can still override that by specifying different values on the make command line. Thus, it is not safe to rely on AC_DEFINE for this particular purpose, and in fact, doing so may not work at all (will not work for prefix itself).
Instead, you should specify the appropriate macro definition in a command-line option that is evaluated at make time. You can do this for all targets being built by setting the AM_CPPFLAGS variable in your Makefile.am files, as demonstrated in another answer. That particular example sets the specified symbol to be a macro that expands to a C string literal containing the prefix. Alternatively, you could consider defining the whole icon directory as a symbol. If you need it only for one target out of several then you might prefer setting the appropriate onetarget_CPPFLAGS variable.
As an aside, do note that $(prefix)/icons/hicolor/scalable/apps is a nonstandard choice for the installation directory for your icon. That will typically resolve to something like /usr/local/icons/hicolor/scalable/apps. The conventional choice would be $(datadir)/icons/hicolor/scalable/apps, which will resolve to something like /usr/local/share/icons/hicolor/scalable/apps.
In your Makefile.am, use the following
AM_CPPFLAGS = -DPREFIX='"$(prefix)"'
See Defining Directories in autoconf's manual.

How to add an include directory based on environment variable in RHIDE without expansion?

The REDHAWK IDE insists on expanding environment variables when creating the Makefile.am.ide file. For example, assume that $SRC_ROOT is /srcpath and I add an include path in the Path and Symbols window of the C/C++ section of my project as below:
${env_var:SRC_ROOT}/include
the generated Makefile.am.ide file contains:
rehawk_INCLUDES_auto = -I/srcpath/include
when what I really want is:
rehawk_INCLUDES_auto = -I$(SRC_ROOT)/include
This is important because this file is used by other team members that have different values for $SRC_ROOT. Currently we have to put the include path in Makefile.am, but then the IDE doesn't see the header files in the directory and sees errors for the code referred to in the missing headers.
Is there anyway to get RHIDE, to not expand the environment variables when it generates Makefile.am.ide?
Not exactly what you are looking for but you can always disable the auto-updates of the Makefile.am.ide by disabling the REDHAWK C++ auto-inclusion builder. This is in the projects properties in the Builders section.
This will allow you to add to Eclipse's Paths and Symbols section without the auto-inclusion builder picking it up and adding it to your Makefile.am.ide.
If you do choose to disable this builder you will then need to manage the addition of new source files on your own.
Youssef's answer is not a bad one, but I've come up with a different way to work around the problem. In Makefile.am, override the redhawk_INCLUDES_auto value to be what I what it to be:
include $(srcdir)/Makefile.am.ide
#Override the value from Makefile.am.ide that may be wrong!
override redhawk_INCLUDES_auto = -I$(SRC_ROOT)/include
This requires one to update any custom include directories in both the IDE and the Makefile.am file, but managing the source files is still automatic.
It still has the issue that the Makefile.am.ide file's contents will be different for other developers which complicates version control. So I don't consider this be a complete answer to the problem.

How to create an EDE project for C++

I have been trying to set up an EDE project for C++ (emacs24 + builtin CEDET) and I'm starting to get desperate because I can't seem to find the way I want the makefiles to be generated. I'm relatively new to Emacs.
I'll try to describe what I'm doing:
I have a toy project set like so:
main.cpp
other/
Utils.cpp
Utils.h
CGrabBuffer.cpp
CGrabBuffer.h
main.cpp includes both .h's inside the "other/" directory. These are the steps I follow to set up an EDE project with this simple directory setup:
Open main.cpp in emacs and do M-x ede-new ; type: Make ; name: main-proj.
Open one of the files in the "other" directory and do M-x ede-new ; type: Make ; name: aux-proj.
Now it's time to create the targets (which I believe are three in this case):
On the main.cpp buffer: M-x ede-new-target ; name: main ; type: program. When prompted, I add the main.cpp to this target.
I repeat the same for the other two targets (Utils which has Utils.cpp and Utils.h and CGrabBuffer which has CGrabBuffer.cpp and CGrabBuffer.h). Here I find the first problem. What type do these two targets have to be? I only want them to generate .o files.
Once this is done, I type M-x ede-customize-current-target to all three targets and I add some include paths, some libraries, etc.
After this, if I call M-x ede-compile-project it doesn't compile because:
It tries to compile main.cpp first; I have no idea how to specify (using EDE) that both Utils.o and CGrabBuffer.o are needed before attempting to build main.cpp.
If I manually change the order (editing the Makefile), it's not able to link main.cpp because it can't find Utils.o and CGrabBuffer.o.
As you can see, I am in the middle of a great mess. Maybe I'm not even understanding what "target" means in EDE. I have also read about the existence of ede-cpp-root-project which has to be specified inside the .emacs file. I haven't tried it because what I think it does is just help with the semantics. It doesn't generate Makefiles, does it? Can I have (or do I need) an EDE project built with Project.el's and the same thing using ede-cpp-root-project for the semantics? Or is it redundant?
Sorry If I misunderstood a lot of things but I'm very confused and being new to emacs makes things worse. Thanks for your patience!
EDIT: with some tinkering and the responses I received I have been able to figure out a lot of stuff, so thanks a lot. What I still don't understand is the use of the ede-cpp-root-project which has to be specified inside the .emacs file. Is it just for c++ semantics? Is it redundant to have the project with Project.el's AND also the elisp lines in .emacs?
EDE is designed to handle many different kinds of projects, usually of a type where the build system was written outside of Emacs in some other tool.
The EDE project type that creates Makefiles for you can do quite a few things, but you need to have some basic understanding of build systems for it to be helpful, and you really do need to customize the projects to get anything of any complexity working.
I've recently added a section to the EDE manual to help with basic project setups that autogenerate Automake files. You can check out the tutorial here:
http://www.randomsample.de/cedetdocs/ede/ede/Quick-Start.html
The same steps will apply for projects that just use Make instead, but Make based projects often have trouble with shared libraries due to the extra complexity.
Mike's answer is quite good, but I think it is ok to just add .h files to the same target as your .cpp sources. It will keep track of them separately.
Another useful trick is to use the whole project compile keystroke (C-c . C) which uses a capital C whenever you change something big. That will regenerate the Makefiles, rerun any needed Automake features, and start at the top.
EDIT: You only need one EDE project for a give project area. The ede-cpp-root project is useful when no other automatic project type works. That's when you create that in your .emacs file so that the other tools that need a project definition, like semantic's smart completion, and tag lookup, will work.
Well, I think I actually have it figured out this time, but it's ugly. Utils.cpp and CGrabBuffer.cpp should not get their own individual targets, because there doesn't seem to be an appropriate target type. Instead, you'll need to create an archive or library, which will automatically compile Utils.cpp and CGrabBuffer.cpp for you. Below, I'll assume you want static, but it's easy to change.
[For anyone to whom archives or libraries are not familiar, they basically just gather up .o files into a separate unit. It doesn't actually make the compilation harder. Read more here.]
1) Follow the first two and a half steps above (including making the main target, but not the other targets).
2) Switch to Utils.cpp and do M-x ede-new-target ; name: aux ; type: archive. When prompted, add Utils.cpp to this target.
3) Switch to CGrabBuffer.cpp and do C-c . a ; Target: aux .
4) Regenerate the Makefile with M-x ede-proj-regenerate. At this point, if you run make in the other subdirectory, you should get the archive libaux.a.
5) Switch back to main.cpp and do M-x ede-customize-current-target. This brings up an interactive emacs customization buffer, which allows you to edit details of the ede configuration. Under the Ldflags section, click [INS]. This pops out a new line that says Link Flag: and has some different-colored box for you to type in (mine is grey). Type -Lother -laux, so that other/libaux.a is included when compiling main. Then, at the top of the buffer, press [Accept], which should save that change and switch back to main.cpp.
6) Regenerate the Makefile with M-x ede-proj-regenerate.
Now, unfortunately, the Makefile makes the main target first, then descends into the other directory and makes that. Unfortunately, this means that a make from the top-level directory will not work on a clean tree. I don't know why this is, because it seems like that would never be what you want in any project that is ever made with EDE. I can't find any way to change that, except for this hack:
7) Do M-x customize-project; under Inference-Rules click [INS]. Then enter Target: all ; Dependencies: aux main ; Rules: [INS] ; String #: . (This last one is just to prevent an error on an empty rule with a tab; presumably an EDE bug.) Click [Accept], and regenerate the Makefiles.
So now, in your top directory, you can just run make, and main should be a working executable.
I'm quickly becoming convinced that EDE is not yet ready to be used by people other than its authors. Despite its size and the amount of effort they've clearly put into it, it is too buggy, too counterintuitive, and just not smart enough. That's a shame. Emacs needs something like this.