Anything missing from what you would like to know about CMake? Anything still unclear? Chat with me about it here and I’ll try to add/fix anything we uncover! 😅
I'd like to say THANK YOU for this video. It was only after watching it, that the key concepts of CMake clicked into my head :D. I would like to ask though, why do you include the "tools.h" as: #include I kinda get using instead of "", cause we made a library out of it (right?), but is there a way that we don't have to specify the whole path to the include, but rather use only the name of the include (i.e. #include )?
@@strangler_xD thanks for the praise! 🙌 Glad you found the explanation intuitive enough. As for the includes. The vs “” is not really that important and is more or less a convention. They would both work in our case. Now as for the path. We _want_ the path to be longer and to include the folders. The reason for this is that there might be many tools.h files in our project. We want to be sure we use the correct one. Having a full project-specific path removes a possibility to include the wrong include. Does this make sense?
@@CodeForYourself Hi, thanks for the reply. Ok, so it's just making sure that a specific file is chosen. If we were to add target_include_directories(tools ${PROJECT_SOURCE_DIR}/our_project/tools/) to the tools' CMakeLists.txt, then we should be able to include as '#include "tools.h"', and still build successfully, right? I'm thinking of a use-case where I want to have multiple "tools" all compatible with an application, and build different executables with a different underlying "tools" library, all by changing only the file I include in my project (I think this can be easily manipulated with CMakePresets), hence my questions. With the full path in the #include directive I would have to change the source every time I want to build. But I guess another way is to always include the same tools.h which would be a "wrapper", and then in that tools.h I conditinally include the actual underlying tools.h path that I want to do (condition being set by a -D command when invoking the build). That way I could keep the absolute path in #include, and not have to invoke target_include_directories() in any of the CMakeLists.txt files. Vis-a-vis scalability and maintenance, what would you deem the preferred approach here?
@@strangler_xD to the first part of your comment - yes, if you change the path to target_include_directories as shown then you should be able to include tools.h with just its name. As for the use-case you suggest, when would you want to do that? In my experience you never want to confuse different files with the same name. These things are hard to debug and probably won't work how you imagine them to. So, while technically possible, I don't think there are many situations where you'd want to do that. The only use-cases I could think of is when using some compiler-specific libraries and including the fallback otherwise. But in this case, we should just set some macro propagated from CMake and use that for choose which include to pick. Does this make sense?
This video is how I found your channel and you just got a like + sub. Man, you were born to teach. Even Kitware couldn't make such a good Intro to CMake. If you do follow up with CMake Installation Command videos, GTest, CTest, etc... your channel will be the best C++ Channel on RUclips. Maybe in a separate playlist, since this may not be Beginner C++.
Thanks man! Glad to hear that you like it! It did take a couple of, well, takes to record it and it's still not perfect but maybe I will improve it further some time in the future. Do spread the word about it 😉 The plan for the next video is exactly what you're saying: hot to include google testing into the project and use it with CMake 😬 This is also not really a beginner C++ course. It just starts with simpler things 😉 it will become more advanced with time.
Really great, glad to discover your cmake videos. As I am looking into strange link errors with static libs made with C, used in c++ apps, but cmake somehow linking wrong things. That lib property thing could be something understand more. Thanks.
Glad I was of some help. One recommendation to debug this type of linking errors is to start small and try to get to the smallest reproducible example first. Good luck!
If you omit the LANGUAGES in the project() command, It will be defaulted to C/C++. I believe in this situation CMake will check for compilers of both languages in the system. So I always specify the language unless I'm going to use both. About the question at the end: Because before this line we gave 'tools' target those properties "PUBLIC"ly, then the 'print_hello' target automatically "inherits" those properties, and there is no need to relink 'tools' to that interface target. And I just forgot to Thank You!
Yep, you're right about the languages. I generally like a more explicit style where things are spelled out and there are as little as possible default values. And yep, you've got it about the dependencies question! Good job! 👍 Thanks for watching!
Also, what can you say about ROS? Is that how you did Robotics or did you use other frameworks? Another question: Have you done/worked with Accelerated/Parallel Programming or any sort of HPC? And sorry for asking so many questions. Your channel is just too good.
We might touch upon ROS. I worked with it of course, I even worked for a company that maintains a safety certified fork of ROS2. An alternative would be to use smth like GRPC using Google protobufs as messages. As for parallel, I did write a fair amount of high performance parallel code but I'm not a GPU guru if you're asking about that.
Буду откровенен, пересматривал 4 раза, и все рано не во всем разобрался. Так и не понял, для чего нам сохранять переменные с каким-то текстом. Однако, отличное видео - нужно просто приложить немного усилий. Мне, кажется, ролика хватит, чтобы понимать 90% cmake файлов. Все четко, и без воды
Дякую за хороші відгуки! Стосовно змінних, загалом всі змінні в cmake це просто текст. І більшість цього тексту зберігається в кеші який потрібен для того щоб зберігати конфігурацію між запусками. А все інше про за я розказую то наслідки цього.
@@CodeForYourself Да, только момент с кешем не уловил. Все остальное кристально. Особенно понравилась презентация на гитхабе. Я вот раньше просто смотрел, ничего не повторяя. Сейчас Вы сказали "не тупить" и выполнить все самостоятельно. Начал это практиковать. Времени намного больше занимает, но после ощущение будто сам все сделал. А если вопросы есть, гпт использую. Еще раз спасибо :-). Подписка, лайк
@ozimandias1858 будьте обережні з гпт, адже він хронічно бреше. Будь які конкретні запитання можна також задавати тут або на гітхабі. Я відповідаю повільніше за гпт, але сподіваюсь що менше брешу 😅
We can definitely talk about ccache too, but I will probably just add it towards the end. I'm trying to cover essential parts first and then talk about the extras. Ccache is definitely an extra for me.
cxx_setup is essentially working like a wrapper for our project (or rather library), right? It's sort of just separating some of the boilerplate stuff from the core of our code?
I wouldn’t really call it a wrapper. It is a kind of library-like cmake target just with nothing to be compiled. It is a dummy target to which we can assign certain properties. Does it explain the notion a bit better?
@@CodeForYourself Ya. I've been playing around with my own project. I knew wrapper wasn't the best word to use for this, but everything we do with it is still inherited by the targets we link it to (because of the INTERFACE visibility). I have seen the other comment regarding the question at the end of the video regarding not including the cxx_setup in the executable's link which makes it clear that wrapper isn't the best word to use. I thought about likening it to how composition works, but couldn't think of a good noun to describe that. So, wrapper was the next thing to come up.
Great video - thanks. But - the manual editing of the CMakeCache.txt appears to break what I have learned: "don't modify automatically generated files". Why does this not apply here?
Hey there. That’s a very good point. I’m not sure exactly what to say here. My best guess is that this mechanism in cmake exists longer than the principle you quote. That being said, even though the cmake cache was seemingly designed to be edited by hand, I don’t remember the last time I had to do that.
@@CodeForYourself Ok thanks for taking time to answer my question. I am relieved by your answer that it is not a necessary / common thing to do. I could imagine it to be relevant to temporarily try something out - but the change is gone without warning on next cmake.
@@heel57yeah. It is mostly a convenient way to explain why it is there in the first place. I found no other good way to explain cmake cache in an intuitive way.
About CMAKE_BUILD_TYPE. You said that It should be set by us in every CMake script. I don't believe that's true. Most of the time we want the ability to choose build type by writing. cmake --build /build --config=Release/Debug Hence we should not FORCE set this variable inside scripts.
Maybe I said it in a wrong way. I meant that CMake expects us to provide the built type on every build. If we forget, I like to set it to release. Of we provide the build type from the command like as you suggest the if statement won't trigger and the build type will remain the one you set from the command line. Does that make sense or am I missing the point?
I believe '--config' only works with multitarget generators (like Visual Studio, XCode, Ninja Multi-Config, ...). However for single configuration generators (Ninja, various types of Makefiles) CMake simply ignores the --config flag and rely on the CMAKE_BUILD_TYPE variable set during the generation step. So If you are, for example, using Makefiles then the you can do the following # config+generation cmake -DCMake_BUILD_TYPE=Release -S . -B build # build cmake --build build -j12
Anything missing from what you would like to know about CMake? Anything still unclear? Chat with me about it here and I’ll try to add/fix anything we uncover! 😅
I'd like to say THANK YOU for this video. It was only after watching it, that the key concepts of CMake clicked into my head :D.
I would like to ask though, why do you include the "tools.h" as:
#include
I kinda get using instead of "", cause we made a library out of it (right?), but is there a way that we don't have to specify the whole path to the include, but rather use only the name of the include (i.e. #include )?
@@strangler_xD thanks for the praise! 🙌 Glad you found the explanation intuitive enough.
As for the includes. The vs “” is not really that important and is more or less a convention. They would both work in our case. Now as for the path. We _want_ the path to be longer and to include the folders. The reason for this is that there might be many tools.h files in our project. We want to be sure we use the correct one. Having a full project-specific path removes a possibility to include the wrong include. Does this make sense?
@@CodeForYourself Hi, thanks for the reply.
Ok, so it's just making sure that a specific file is chosen.
If we were to add target_include_directories(tools ${PROJECT_SOURCE_DIR}/our_project/tools/) to the tools' CMakeLists.txt, then we should be able to include as '#include "tools.h"', and still build successfully, right?
I'm thinking of a use-case where I want to have multiple "tools" all compatible with an application, and build different executables with a different underlying "tools" library, all by changing only the file I include in my project (I think this can be easily manipulated with CMakePresets), hence my questions.
With the full path in the #include directive I would have to change the source every time I want to build.
But I guess another way is to always include the same tools.h which would be a "wrapper", and then in that tools.h I conditinally include the actual underlying tools.h path that I want to do (condition being set by a -D command when invoking the build). That way I could keep the absolute path in #include, and not have to invoke target_include_directories() in any of the CMakeLists.txt files.
Vis-a-vis scalability and maintenance, what would you deem the preferred approach here?
@@strangler_xD to the first part of your comment - yes, if you change the path to target_include_directories as shown then you should be able to include tools.h with just its name.
As for the use-case you suggest, when would you want to do that? In my experience you never want to confuse different files with the same name. These things are hard to debug and probably won't work how you imagine them to. So, while technically possible, I don't think there are many situations where you'd want to do that. The only use-cases I could think of is when using some compiler-specific libraries and including the fallback otherwise. But in this case, we should just set some macro propagated from CMake and use that for choose which include to pick. Does this make sense?
Best explanation ever found for cmake
@@rishiniranjan1746 thanks! This means so much to me! 🙌
05:34 The best way to explain things. Great content! Thanks so much!
Great video! This is what I will share if my teammate need cmake tutorial
Glad you enjoyed it, tell me how it goes ;)
This video is how I found your channel and you just got a like + sub.
Man, you were born to teach.
Even Kitware couldn't make such a good Intro to CMake.
If you do follow up with CMake Installation Command videos, GTest, CTest, etc... your channel will be the best C++ Channel on RUclips. Maybe in a separate playlist, since this may not be Beginner C++.
Thanks man! Glad to hear that you like it! It did take a couple of, well, takes to record it and it's still not perfect but maybe I will improve it further some time in the future. Do spread the word about it 😉
The plan for the next video is exactly what you're saying: hot to include google testing into the project and use it with CMake 😬
This is also not really a beginner C++ course. It just starts with simpler things 😉 it will become more advanced with time.
Very informative video. Followed your previous course at UBonn years ago and it is so nice to refresh old concepts again. Thank you for your work.
Thanks for the kind words! 🙌
Really great, glad to discover your cmake videos. As I am looking into strange link errors with static libs made with C, used in c++ apps, but cmake somehow linking wrong things. That lib property thing could be something understand more. Thanks.
Glad I was of some help. One recommendation to debug this type of linking errors is to start small and try to get to the smallest reproducible example first. Good luck!
If you omit the LANGUAGES in the project() command, It will be defaulted to C/C++. I believe in this situation CMake will check for compilers of both languages in the system. So I always specify the language unless I'm going to use both.
About the question at the end: Because before this line we gave 'tools' target those properties "PUBLIC"ly, then the 'print_hello' target automatically "inherits" those properties, and there is no need to relink 'tools' to that interface target.
And I just forgot to Thank You!
Yep, you're right about the languages. I generally like a more explicit style where things are spelled out and there are as little as possible default values.
And yep, you've got it about the dependencies question! Good job! 👍
Thanks for watching!
Also, what can you say about ROS? Is that how you did Robotics or did you use other frameworks?
Another question: Have you done/worked with Accelerated/Parallel Programming or any sort of HPC?
And sorry for asking so many questions. Your channel is just too good.
We might touch upon ROS. I worked with it of course, I even worked for a company that maintains a safety certified fork of ROS2. An alternative would be to use smth like GRPC using Google protobufs as messages.
As for parallel, I did write a fair amount of high performance parallel code but I'm not a GPU guru if you're asking about that.
Буду откровенен, пересматривал 4 раза, и все рано не во всем разобрался. Так и не понял, для чего нам сохранять переменные с каким-то текстом.
Однако, отличное видео - нужно просто приложить немного усилий. Мне, кажется, ролика хватит, чтобы понимать 90% cmake файлов. Все четко, и без воды
Дякую за хороші відгуки! Стосовно змінних, загалом всі змінні в cmake це просто текст. І більшість цього тексту зберігається в кеші який потрібен для того щоб зберігати конфігурацію між запусками. А все інше про за я розказую то наслідки цього.
@@CodeForYourself Да, только момент с кешем не уловил. Все остальное кристально. Особенно понравилась презентация на гитхабе.
Я вот раньше просто смотрел, ничего не повторяя. Сейчас Вы сказали "не тупить" и выполнить все самостоятельно. Начал это практиковать. Времени намного больше занимает, но после ощущение будто сам все сделал. А если вопросы есть, гпт использую.
Еще раз спасибо :-). Подписка, лайк
@ozimandias1858 будьте обережні з гпт, адже він хронічно бреше. Будь які конкретні запитання можна також задавати тут або на гітхабі. Я відповідаю повільніше за гпт, але сподіваюсь що менше брешу 😅
Great video. Thank you. Maybe you can ad ccache to cake in follow up video?
*add
We can definitely talk about ccache too, but I will probably just add it towards the end. I'm trying to cover essential parts first and then talk about the extras. Ccache is definitely an extra for me.
cxx_setup is essentially working like a wrapper for our project (or rather library), right? It's sort of just separating some of the boilerplate stuff from the core of our code?
I wouldn’t really call it a wrapper. It is a kind of library-like cmake target just with nothing to be compiled. It is a dummy target to which we can assign certain properties. Does it explain the notion a bit better?
@@CodeForYourself Ya. I've been playing around with my own project. I knew wrapper wasn't the best word to use for this, but everything we do with it is still inherited by the targets we link it to (because of the INTERFACE visibility).
I have seen the other comment regarding the question at the end of the video regarding not including the cxx_setup in the executable's link which makes it clear that wrapper isn't the best word to use. I thought about likening it to how composition works, but couldn't think of a good noun to describe that. So, wrapper was the next thing to come up.
what fonts you use in terminal? i liked them
I’m not entirely sure which one I used back then but I have mostly converged on using Fira Code everywhere now.
Great video - thanks.
But - the manual editing of the CMakeCache.txt appears to break what I have learned: "don't modify automatically generated files". Why does this not apply here?
Hey there. That’s a very good point. I’m not sure exactly what to say here. My best guess is that this mechanism in cmake exists longer than the principle you quote. That being said, even though the cmake cache was seemingly designed to be edited by hand, I don’t remember the last time I had to do that.
@@CodeForYourself Ok thanks for taking time to answer my question. I am relieved by your answer that it is not a necessary / common thing to do. I could imagine it to be relevant to temporarily try something out - but the change is gone without warning on next cmake.
@@heel57yeah. It is mostly a convenient way to explain why it is there in the first place. I found no other good way to explain cmake cache in an intuitive way.
About CMAKE_BUILD_TYPE. You said that It should be set by us in every CMake script. I don't believe that's true. Most of the time we want the ability to choose build type by writing.
cmake --build /build --config=Release/Debug
Hence we should not FORCE set this variable inside scripts.
Maybe I said it in a wrong way. I meant that CMake expects us to provide the built type on every build. If we forget, I like to set it to release. Of we provide the build type from the command like as you suggest the if statement won't trigger and the build type will remain the one you set from the command line. Does that make sense or am I missing the point?
I believe '--config' only works with multitarget generators (like Visual Studio, XCode, Ninja Multi-Config, ...). However for single configuration generators (Ninja, various types of Makefiles) CMake simply ignores the --config flag and rely on the CMAKE_BUILD_TYPE variable set during the generation step. So If you are, for example, using Makefiles then the you can do the following
# config+generation
cmake -DCMake_BUILD_TYPE=Release -S . -B build
# build
cmake --build build -j12