CppCon 2017: Mathieu Ropert “Using Modern CMake Patterns to Enforce a Good Modular Design”

– Hey guys Well I hope you didn’t have too much of a big lunch ’cause I’m gonna talk for one hour about build files (audience laughing) Just so I know like to get a better feel of my audience Who here likes to write build files? (audience laughing) Okay keep your hands up Get your hands up Then who likes to write especially CMake list files? Oh okay For those watching on YouTube that was almost everybody (audience laughing) Alright, yeah I know, I know It’s a pain We usually think that it could be delegated to somebody else I mean for some of my time, maybe not me because I’m like very super into make files and build system maybe too much, but for most people, I guess if your manager came to you and told you I have a way that I don’t know this external company or this guy down the hall is gonna write all your build file for the rest of your life, you would say, “Okay great, great.” So yeah, for most of us it’s a problem It’s like a hassle, something that we would like to not do But, I start working with that for some years, and I discovered that actually it can have some purpose For example, do you ever start with a small application you built where the dependency graph looked like this Well it’s very simple You have four leaves and a simple diamond pattern You let that live and after I don’t know a few month, years, you get something like that Sounds familiar so far? All right, yeah that happens to me too So what are we gonna talk about today? We’re going to see what’s the theory behind modular design The idea that you should keep a clean graph dependency, a clear code architecture and how we can integrate CMake into that Technically speaking, any build system worth its salt should allow you to use some patterns that will give you the same results I’m just you know use CMake because that’s what everybody else uses if I trust Github or any Open Source project really But, really think of that as just an illustration Any build system should be able to provide you with the same thing And in fact, most of what I will tell you today is taken from other build systems, some that are usually considered more modern that you also can have simply with CMake without the, well, the big pain of changing entirely your build system A few word about me I’m Mathieu I’m from France You might have heard it already I work at Murex and since one year, I’ve been a contributor to Conan, and all I got for my pain was this lousy t-shit Along the way, I discovered a few things about CMake, about packaging, and about how do we use all that to make better code So let’s talk a bit about CMake First thing that most people think is that CMake is a build system Well it’s not Technically speaking, it’s a build system generator You tell him that you want to build a project, and all he does is generate the build file for somebody else Make, Ninja on Unix, Visual Studio or something else on Windows It just does that It doesn’t build by itself It just meet that description for the generator you use It’s, well, almost 20 years old right now And, it’s used in lots of Open Source projects You might recognize a few And, that’s not limited to Open Source Private company also use CMake internally And, so what’s the big deal with CMake? Well basically, it’s maybe not the best, but it’s the less painful solution we have to handle portability in C++ because the language can be portable, your libraries can be portable if your build system is not, if you have to write like again your build files for every system, you’re not portable And, what CMake does is that you can finally write the thing once and have it work everywhere And, as we all know, it was a big success For example, if you want to invoke it on a Windows machine that’s how you do it And, on a Unix machine, that’s how you do it All right, almost portable I would say But, we’re not so far So what do I call modern CMake?

You might have seen that was the title of my talk I’m not entirely fond of the title myself, but you know there’s modern C++ Why not modern CMake? It’s something that’s been available for some time The first I would say first compatible release would be 2.8.12 In practice a few month after that, they move to the new 3.0 release which has a few more features, but exactly the same philosophy And, it’s very important to know that it’s 2.8.12 because it’s not a batch release They changed that in the new three branch, but in branch two, the last one was also a feature release It’s not 17 versioning So when I say 2.8.0 and 2.8.12, there is like a huge array of feature that you’re missing between the first and the last revision So how do I know that any project I open on Github is not using modern CMake? Well that’s easy I just have to look at the top line of your project, and I see require 2.8 None of the feature are guaranteed to be available Even more than that, if you can’t have them because you have a more recent CMake, CMake may disable them because he wants to be compatible That’s what you’re telling him Well yeah that makes me sad because you’re missing out Let me explain exactly what you’re missing What you’re missing is the opportunity to have your build system help you do a better design But, before I explain that, let me go back to what I call modular design The idea was taken from John Lakos talk that I had the privilege to watch last year Three part talk, very interesting Like 1,000,000 slide in three hours It comes from his book which is about the same length I think like 1,000 pages And, I will try to summarize what I’ve taken from that for this purpose So obviously it will not be everything ’cause that’s like a huge topic And, John if you’re watching this, I’m sorry I’m gonna make mistakes I’m gonna forget something, but the idea is there I hope so So to explain modular design, I think the best idea is to take a simple example Imagine for a second that you join a small startup There’s like maybe two or three developers, and you have this big idea that you are gonna provide a service to compare and find the best taxi ride in your region So you have this first iteration You have to deliver a minimal product just to demonstrate your nice algorithm to your investors and obviously get some money and get funded for the rest So if you try to apply some kind of modular design rules, you try to keep concerns separated So we’ll have a first library that will handle the taxi prices, the description of your objects and a few operators to manipulate them, and you make sums or comparison, whatever You will have a second one that we’ll use to describe a client order what’s his name, what’s his profile, where does he come from, where does he want to go, that kind of stuff And, the final is the fare which is the result That’s just a very schematic example But, the idea is that to build your calculator, you actually depend on three modules which are completely independent, and that you can test even without your super nice algorithm That’s the point So that part usually we get it right because it’s like four libraries, and we are like two developers Some time passes, you see your investors We are very happy And, you say all right, go for it Develop me a full service now The proof of concept was okay Here is your funding Okay so you have to take to talk to the rest of the world So first you write some kind of JSON passer that’s able to retrieve the prices from all the companies in your area Okay then you want to serialize your clients orders, so you had some SQL database, and you add the library to do the serializing Note that at each time, we decouple the problem First with technical dependency on the JSON, on the SQL library, I still have the class that represent my object And, then I have one library that combines both The idea is that I can still work with them in isolation If tomorrow I decide that SQL is not the future, that it’s no SQL or that it’s whatever, I can change that with no impact on the algorithm, on what is making my company money Of course we finish with another serializer

for the output of our algorithm in JSON Okay we’re still fine We have followed the practices Again we’re still a small startup That’s fine Okay we scale up even more Our clients are very satisfied We can finally put all that in one nice service, so we add the dependency on the REST server library which itself is using some HTTP library And, we create at the top the simple router that takes a request, check the prices, and gives you a JSON response with the best price you can get for what you ask With me so far? Okay that’s a theoretical example That’s maybe what you might have seen in some classes, but then there’s practice And, in practice Well it might look more like this You had some dependency that are kind of dubious because you maybe were in a rush, or maybe you just didn’t notice it It just went through code review, or you were tired Well we have lots of excuses Or, I guess we give ourself lots of excuses Anyway, in practice your code is not like this because you have circular dependencies, so in practice your two modules, only one here, and one there So directly if you start looking at your graph, it’s not that good You start to have a mix of concerns, things that are not really in the same domain that are bundled in the same library, and you cannot already test one without the other Well it’s starting to get messy, but you can still test most of it But, in practice if you let that pattern go, and go, and go, you end up with something like this which is one big blob which is your service and then maybe a few external libraries And, if you’re unlucky, you may have even circular dependencies between third party libraries or the things that you consider really technical Does that seem familiar to anyone? Okay, all right You were silent I had a doubt for a moment like is that only me? Now I’m convinced So what’s the basic idea behind modular design? It’s just that you keep control of your dependency graph You make sure that when a library needs another library, it’s explicit, and it can be checked by some kind of tool or reviewer to ensure that you are not creating a monster, that you are not going through a huge monolith with circular dependency, with nothing you can reuse or test in an isolated way And, of course without so much cost In this example, you cannot reuse anything of your nice algorithm without the whole stack In this one, it’s still possible And, the farthest we go, the better And, then there are modern build systems I’m not sure which one I would call the first one We might have heard about Bazel at Google or the other clones that came up afterwards like Buck or Pant, whatever They all have the same philosophy behind them It’s that they are all very explicit in what you say You are really explicit about what you ask in term of build You only ask for what you use, and the system will forbid you to use something that you did not declare And, that’s the key If you do not declare something, but you can use it, you will have a problem because it will slip through at some point And, that exactly the idea of a modern build system It’s that it protects you against bad patterns, and it helps you leverage on that to make sure that you keep a clean architecture So if you come back to CMake, what happens today in most projects in what I call not so modern CMake? If I tried to build I don’t know a small project with just a TCP client and its own TCP library Very simple, one library, one executable, that’s it Well, what do you think of that? Does this sound like something you might have seen or even written? Seems okay First thing, I had a subdirectory which is my library I declare an executable I add the necessary include directory, possibly some flags if I need like IPv6 in that case And, then I tell CMake that my binary depends on the library The problem with that, sorry, the problem with that

is that I’m not expressing myself in terms of modules here I’m not saying CMake I have this binary It needs this library I’m telling CMake I have this binary It needs those headers It need those flags And, then it needs to link to that I’m not talking about modules I’m talking about build flags And, there is a world beyond those two You can miss a lot of things, and it doesn’t scale If I build up on my TCP library for another project Then I want, I don’t know, an HTTP library, and then a REST library What will happen to my build flags? Well TCP is quite clean I just have minus TCP and minus D IPv6 Then I do the lib HTTP I have to copy paste those flags plus the flags for the library itself And, then again same thing for the library just up ahead It doesn’t scale Every time you have a public dependency, that means that you will have to take all the public flags from the library you’re using and copy them in your CMake list And, if you go to like three, four, five iteration, you end up with like, I don’t know, three lines of flags that you have to add to your library or to your program to be able to compile I’m afraid that’s what I see in some projects What do you do usually? You just give up because it’s just a nightmare to maintain if you have to change the library that’s at the root, you have to modify everything in your system So what do you do? You go to the top CMake file, and you say all right everybody can include that directory Everybody can link to that, done And, that’s the only sane way you might think you can do it And, I won’t blame you for that I did the same thing And, the idea is that CMake has another way Most build system have another way Because if you’re thinking about flags, you’re not thinking about modules You’re not thinking about architecture You’re just thinking in terms of minus E, minus D It’s a mess It has no sense There is no way for you to try to reason about it and think about all right am I including this stuff Is there like a good reason for it, or am I just I don’t know grabbing things that I should not, things that maybe depend on me while I’m depending on them? How can you know? How can you tell? Personally I can’t The other way around If you just declare modules, if you just say, I have lib B, and it depends on lib A Even if you scale that to 100 or 1,000 module, I mean every intern at your company can take that, do a graph, output that in a dot file and just draw you the graph And, I’m pretty sure it’s easy to write some kind of sanitizer or check tool that you can run on your Git commit on your pull request to tell you all right you’ve introduced a circular dependency, you cannot do that If you reason in term of modules, it just become a graph If you reason in term of a huge list of flags, well you can’t do anything You’re stuck So the idea behind a modern build system is simply to protect you from circular dependencies, or at least, tell you when you’re doing it I didn’t think you could have a good reason, but some of them will let you override that if you really need to Of course, like I said, the idea is that you can reason at module level really not talk about flags And, basically it means that the build system is doing more than you’re telling him It’s not just a script file that’s doing blindly what you’re tell him like a dumb robot He is trying to make meaning on what you’re building and say hey, hey, hey I’m not in your place, but if I were you, I would not do that I’m pretty sure you’re not doing what you should be doing The same way your compiler can tell you, even if it doesn’t stop you, that you are returning I don’t know the address of a local variable or something else that in 99% of the case is a bad pattern, and that you should avoid So in practice how does it work? It’s simple Each module will define of course the build flags it needs because well you have to define them somewhere They’re not going away They’re just localized You just tell all right this is my module This is what it needs to build Then you say all right this is what I require This is the dependencies I use But, you talk about dependency You don’t talk about flags You do not look at the other modules internal

That’s not your concern You just say I want lib B Give me the flags I need to compile and link with lib B Do not look at the build file and say okay, in that case, I may need to put that flag because I’m using that feature That’s not maintainable Of course, you need to split your own build flags in two sets, private and public, that’s exactly like the object concern of implementation versus interface Private flags is your implementation, the flags that you need to build But, once you’re built, you can throw that away, nobody cares You just needed that to get a binary The second set is the public ones It’s like your public includes the define that will affect your compilation, all that stuff And, that your clients will also need to be able to compile And, of course the interfaces are transitive That means that if you have a private dependency, you take their modules, but then it stops If you have a public dependency, it adds to your public interface For example, if we look at what we had in previous example with TCP, HTTP, and REST, it’s all public dependencies So the flags have to be repeated at each step If that was a private dependency, it would stop at the first consumer because it is linked to build, but then since it’s private, it’s not seen by the rest of the world The rest of the world does not need to have those flags to build successfully And, of course, you still have flags I mean you have a respective set of flags You only care about the flags you will use in your module, but you can still put them, all the ones, you still used in the past, you can still have them And, I’m not telling you to stop using flags at all You still need them I mean just minus E, just minus W, whatever You still need them, but you need to localize them You need to make sure that it does not escape your CMake file So all that is nice, but how ’bout CMake, right? That’s nice I show you something that’s taken from theory like maybe some nice system that’s going on at another company But, you are using CMake I am using CMake I’m publishing stuff on Github Can I use that with CMake? And, I would not be here if the answer was not yes, you can There is actually an answer What’s the idea? The idea is simple really Well you still use the old add library, add executable That part is still the same I didn’t ask your familiarity with CMake, but I hope that everybody’s clear on that so far Okay, great And, then every time you have to put some flag, you sue the target variant of whatever you need to set some flags I will give some details after that Then if you want to declare dependencies, you use target link libraries It’s helpfully named because if you want to link with like the direct library with a path, and if you want to link with a module, with a project and take its interface, it’s the same syntax It’s really a limitation of CMake I would wish there was another keyword so that you can distinguish between those two There is not So yeah, it’s called target link libraries, but in practice, you’re not just telling CMake that you want to link to a library You’re telling CMake I’m using that dependency Please give me all the flags I need to build successfully And, of course every time you have to specify a property for your files or your build files, you say if it’s public or private It’s an example Okay first part is easy You start by requiring, well technically you could put 2.8.12, but I think 3.0 is not something too big to ask for most of the world It’s five years old now You should be fine with that Of course you can go crazy, and you can have 3.9 if you want I won’t stop you On the contrary, there are lots of interesting feature in that, but at least 3.0 Then well first counter example, you might still declare some flags at the top level Why? Well that comes from my experience And, in my experience, there are some kind

of compilation flags that you do not want to localize for some particular module You want to put them everywhere And, the most important is anything that’s a combination of Werror and W something Because there is nothing worse than changing your code and having it break because in your header there is something that will not compile in one of your clients because he’s more strict than you I don’t know if it happened to you guys, but it happened to me a lot of time, and that’s very painful So I said that some flags might still be better off at the top level to make sure that all the project is on the same page And, I would ask the same thing for anything that affects the ABI like a standard level that kind of thing because if not, you will get some incompatibilities All right then you still do your add library Nothing fancy here, the same thing you’ve been doing for I don’t know how much you’ve been using CMake, but that part doesn’t change All right, and now we come to the meat of the thing First you want to declare some public headers, so you say all right target include directories You say it’s public and you need the path That tells CMake all right in the build interface of my project anybody who want to use my project will need this include directory to find my headers If you have some public headers, for example in your SLC directory, you just add the same thing with private You’ll be able to include them in your project Anybody else won’t see them If you have some settings, something that depends on the config of CMake whatever, you can also put them with the compile definition or whatever In this case, it’s a public setting But, if it would have been a private setting, it would just have said private instead That’s the same idea If the setting will have an impact on your public headers like change the size of a structure or maybe hide some declaration, you need to make that public If it’s only internal detail like I’m gonna use this algorithm internally or that algorithm and that don’t change your API or implementation, public implementation, you can put it private It’s fine And of course, then you have to declare your dependency And again, I’m sad that there is not a special keyword that’s different from the old one to express that, but trust me that if I said target link library something, ABC and ABC’s a project, I will get all the public flags that are declared I will get the link flags I need, and that’s recursive If I need transitively some include flags or some link flags, I will get them It will even go across static libraries because as you already know I think static libraries are not linked So if you have a dependency inside of static library, CMake will remember that And, the first shell library or executable that it encounters will link to it It’s taken care of for you And, of course if you have a private dependency like something that your implementation relies on but that’s not visible for your headers, you can put it private It will work too, and it will not be seen by your consumers Meaning that for example if you use Boost, but if you do not want the rest of the world to see Boost, or if you want to make sure that the rest of the world will not use Boost unless it is declared, you make it private And, only people with explicit reference to it will see it And, that’s a huge point because what happened a lot in my experience is that everything that can be found through auto completion inside your IDE will get used by people even if it’s not publicly declared, but it’s available through transitive dependencies So the less that you have in your public interface, the more private you got, you’re sure that people will have to be explicit about them, and you reduce the risk that your architecture will start to go bad like I said in the first slide If you got header-only libraries which is kind of the fashion today, you can simply declare an interface library Interface is a peculiar keyword in CMake that tells it that something belongs to your public interface but should not be used to build your library Of course because it’s a header only You have nothing to build So if you have nothing to build, but you want your clients to see it, you make it interface

And, you can even link to something You can say for example my header-only libraries will need this client to be linked to that You can add a link dependency It will work CMake will take care of everything because that may happen You may have header-only libraries that needs something that’s not header only It will work Like I said, nothing to build, think interface Now that we’ve seen most of the good patterns, I want to take just a few seconds to recognize the antipatterns, the bad things That’s the kind of thing when you open a CMake list that tells you that you probably need to rewrite it a bit So of course everything that affects all targets like include directories, add definitions, link libraries Those kind of thing are evil If you put them on your top level, everybody in the world will be able to use them Everybody in the world will be able to include that headers, and if your some reason the code does not require a link, like for example header-only libraries, or inline templates, whatever, you will not even get a compile error People will start creating hidden dependencies through other modules, and they will not even see them Of course link libraries, I think CMake have told people like for 10 years now to stop using it because it just means every project in the world should link that I’m not sure anybody in this room will be using this But, just in case, don’t Okay then Yeah? – [Audience Member] There’s a caveat Those macros that you mention They actually don’t affect all targets They only affect the targets in that– – Yeah I know only the targets you declare in this file, and all the subdirectories you include unless you start a new project – [Audience Member] Right So if you use those macros, there will be a huge list in the subdirectory that I’m calling – I will not say it’s okay to use at any point because they will not affect your interface at all So if you declare an include directory for example that your clients will also need because for example they appear in your headers, they will have to copy paste that also to be able to work I really not recommend using that at all – [Audience Member] Well there are legitimate uses That’s fine – I will be happy to discuss that with you afterwards because frankly I’ve not seen them in my career Maybe for a very small project just like you know the tests or something, for that yeah But, for a huge application, that’s coming to bite me at some point And, I will get exactly the same warning against using target include directories to include anything outside your project because if you include something outside your library, well you’re breaking the rules again You’re not trying to use a dependency You’re trying to use headers from somebody You’re trying to pull something that’s not yours to use it without declaring explicitly I have a dependency to that module And, then you’re breaking the rules of talking about modules instead of talking about implementation And, that’s the thing here What I encourage you to do is to declare dependencies to modules not build flags because it’s awful to reason about at scale Since target link libraries is an old marcos and since CMake did not make a new one, you can forget to put public, private, or interface, and it will work Which one of the three it will do if you do not put public, private, or interface, to be honest, I can’t tell you without looking at the doc So my recommendation is do not use it Just always tell if it’s public, private, or interface And, of course target compile option, I would recommend you to use caution because if you put like I said some Werror, you might have some surprises because your dependency change, and they do not have the same level of pedantic as you do, or maybe simply you do not use the same ABI Like I don’t know you ask for C++ 11, and for some reason another library asks for C++ 03, you do not use the same runtime You’re gonna get into trouble So I would keep that at top level All right if you remember this, I think you get like maybe 90% of what I call modern CMake because you get away from the flags You got away from looking at the bits

and the implementation of all of your modules, and you move to another layer of abstraction You’re really thinking in terms of modules, in terms of what is my implementation, what are the interfaces I use You do not care about how people implement their modules Because another problem is that if they change, you have to change too unless you declare dependency, and then the build system does that for you And, that’s the whole point And, since we have some time, I guess we could talk about the rest because of course the 10 last percent are the least used but might still come handy to you The first example, and I think the most common case that I did not address yet is external dependencies because we all use third parties, I think, or most of us use third parties And, well they are not always built with CMake or always built with that instance of CMake you’re running at some point So you have to grab some packages For example, here I needed GTest I read the doc about the find package of GTest which said that GTest should be built with threads because on some platforms, on some compilers you need to link with threads too So I require also the thread packages Then I create my executable, and since GTest provide me some nice macro, I can add the GTest include to my directories, and I can link to GTest And, that’s wrong Yeah, that was a trap The problem is that you are falling back to the old flags approach You are not telling CMake that you are depending on GTest You’re telling CMake that you want to include GTest headers that you want to link to GTest, and that you want to link to GTest dependencies And, should that change, you have to rewrite your code And, fortunately for you, CMake heard that, CMake saw that, and in their recent versions, they changed their finders to be able to export targets too So now if you take at least 3.5 for example with GTest, you can just say all right I require GTest GTest which is the name of the GTest main if you want GTest to generate the main function for you And, that’s that It’s done It will call your threads for you if you need them If GTest implementation completely changed tomorrow and requires something else, it will also take care of it You will not have to change anything There has been some effort, like I said, in CMake to add some new finders The first one was OpenSSL in 3.4 Yeah, that took four release to think that third parties was an issue, but we’re getting there 3.5 was big We got Boost, we got GTest Already I guess like half the dependency I require on new project are there You got some graphical libraries 3.6 bring us Package and Config which is pretty nice because it’s not just find package and config It’s like if you use CMake to find a PC file, it would automatically translate that into a CMake project definition for you So you can just say okay I require that PC dependency You’re all set Any Package and Config package installed on your system, you can require it with modern CMake just with that patch which is I think pretty cool at least on Unix The only problem is that I never seen anybody using PC on Windows, so that’s not exactly portable But, well on some environment that might really be handy And, more recent version we add OpenGl, OpenCL, BZip, and all that kind of stuff So yeah, if your manager is a bit old on CMake, if your file structures a bit old, all the more reason for you to ask him to move to a more recent version You have all the finders set up for you, and that will simplify your code But, what happens if there is none? Because as you have seen there are some of them, but I don’t think that’s the whole C++ package community here Well I think some of them may be missing So what do you do? Well first option obviously, you can just contact the maintainer and ask him nicely to provide one You may or may not have some results You may also have some arguments For example, you can tell him, as I can tell you today, that if he builds his package with CMake, he just has to add a few instruction at the end to ask CMake to generate that finder for him

Because when you do make install with CMake, you can also tell CMake to generate a dot CMake file that act as a finder I think Daniel Pfeifer did a nice talk on this and a lot of other things on CMake at C++ Now back in spring, and it explains all of that Of course if you are publishing a library, I encourage you to do one even if it’s not with CMake If it was CMake, it’s simple really Really, you just have two instruction, and it generates them for you If it’s not CMake, well it’s not that hard What do I have to do? Well first of all of course I have to do find library to find the library to just make sure that it’s installed on the system And, CMake will take care of the question is it Windows or Unix? Do I have to have a dot DLL, or dot SO, or dot LIB depending on the platform? You can tell CMake that you add the library as an imported target And, then you say all right I want to include those directories and these dependencies, and I have a nice build interface with an external project Easy, well almost too easy Yeah, I hoped that by writing that that would have worked, but it didn’t Turns out that CMake maintainer left me a little surprise in that in that it’s a bit more complex For internal reasons you cannot use target whatever on an imported target It doesn’t work CMake will throw you out Fortunately it’s only a wrapper The target whatever is just a wrapper It’s just telling CMake go through the list of variables that are defined in my package and set some values So you can do it by hand I won’t say it’s pretty like you can see, but it does the job Simply, well you still add your library You have to set a property for the location You cannot directly tell that when you add the library, but you can just set property And, same thing, all the things you set like public, or private, or whatever it just a set of variables that’s added to your project That’s how it works with CMake behind the scenes That’s not even relying on implementation details That’s something you can find in the CMake doc That’s not something I recommend you to use, but in this case, you don’t have a choice unfortunately until maybe CMake patches that Well okay it’s not pretty, but it fits on one slide So well that’s not that terrible Can we have easier alternatives? Well yeah, there are some But, as some French famous mathematician said it doesn’t fit on the margin of this talk, so I won’t be able to give you all the details Still like I said before Daniel Pfeifer did a very nice talk about CMake which is called Effective CMake I think, yeah Effective CMake It was in Aspen at C++ Now It explains lots of thing about CMake from generating finders to using CMake to set some compatibility flag for you, checking the standard support, whatever, you name it, it’s got it I think it was voted like most helpful talk of the whole convention So I really encourage you if you’re into CMake, if you have to use CMake, just go look at it You will see lots of interesting things So to summarize a bit what we’ve seen today together First things, what’s modern build? Modern build is about keeping your flags to yourself Do not try to expose your flags in the code of the others Do not look at the code of the others to try to get the flags Just keep that to yourself It’s your private bits It’s your problem CMake will all know the rest You think in terms of modules really You think about the graph You know it’s easier when you think about it It’s just like take a white board and do some architecture like we all like to do when we start a project And, then we fall back into flags because we are out of time But, the idea is that you can still do that the whole life of your project You can always go back to all right let’s put that

on a whiteboard Let’s make a nice dot file or whatever and see okay does that architecture make sense? Or, am I trying to insert circular dependencies or hidden dependencies? And, all the rest, all the transitivity, all the hidden internal flags that you need to pull, you let the build system do that Again, I’m talking about CMake here, but I don’t know what you use at home Anything should be able to handle that If not, I guess it’s time for a feature request So for CMake, first of all take three dot something The most recent the better, as you have seen, there are some nice finders to this Use the target something alternative for macros unless we’re talking maybe about compile option, but other than that, use the target alternative Always specify if a property is public, private, or interface You are trying to expose something to CMake It needs to know the level of visibility the same way that when you put something in a class you have to wonder about is it public or private, well it’s not protected in that case But, is it public, private, or both And, of course you have to link against a target to get all these properties It’s still not pretty I would gladly like to have, I don’t know, target require module or something that sounds more like effectively what we are doing, but it’s what it will do behind the scenes It’s not just I want to do minus L that library It’s more than that, and it’s what you should do For external packages, well your first option is simply to use modern finders because some of them are provided If not, write them Ask the manager to write them Or, if you cannot, well there are some options Like I said CMake can generate one from you just by the build definition of your project when you run the configure and the make install It can do that for you If it’s an external system, you can ask the maintainer, “Please, please, please, please, please “could you make the finder for CMake for me?” If it’s a PC file, it’s automatic And, if none of that it’s possible, well I guess you can try a package manager All right, thank you all for coming And, I think we have a bit less than 15 minutes for questions (audience clapping) We have two mics I think it would be better for you, you if you could come down – [Audience Member] So one pain point for us has been some of the find packages that return hard paths for the library, and then if it gets built somewhere else as part of a different build closure, that path is now wrong due to things like sim link farms So like OpenSSL has, at some point, been an offender in this So how would you recommend us be able to take advantage of dynamic libraries like that without breaking the build further down – I’m not sure I get that because when you run find library, it tries to look for files So it should not return if it’s not found You know you can add the required, and when you do find package, you can tell required, and if the finder fails because the library isn’t there, it will stop I don’t know if that’s your problem – [Audience Member] So say you had two libraries, the first one got built against OpenSSL, and it had the actual link on the path to the host for OpenSSL that you linked against And, then it goes off to another section in your build fleet There’s another large section of sim link farms that are built That path is no longer the same, so when you go to link against project A, the path no longer works, and you have linker errors – You’re talking about two different instance of CMake here right? Like you do a first run of CMake, you produce some libraries, but they’ll have some dependencies, and then you will import them into another CMake instance Well I would tell you that’s what package manager are for Really I would suggest you to look at what exist

and check with that because doing that by hand on the same machine it’s possible because you can use sub modules in CMake and have everything in the same place But, if you build in different stages, I really encourage you to look at package managers because if it’s just one step it’s possible, but, as you illustrate, if it’s a few steps, it gets a nightmare to handle recursively And, the easier way if you want to make sure that you keep everything, and the package are relatable It’s much easier to do with a package manager – [Audience Member] Okay, thank you – [Audience Member] You said something about keep your compiler flags to yourself I cannot appreciate that more I mean that is such truth Because a couple weeks ago, we have a whole bunch of external libraries, and a couple of weeks ago, we upgraded one of them And, unfortunately one of their most recent version, they have a compiler settings file in which they have declared their compiler flags as public So I built the externals and tried to build our code base, and they had ethno exceptions in there So my quick and dirty solution was go to the compiler settings dot TXT and do a CMake string replace except no exceptions and replace them with empty strings That was ugly I know, but was there a better way to do that? – My suggestion would be that first if possible do not set, inside the CMake list, do not set compiler flags I mean do not set like minus STD You can require You can like ask CMake is this compiler with the flags I’ve been supplied able to use C++ 14 or whatever? That’s okay You can make checks But, I think you should not try to set things It should be delegated to the invocation of CMake when you can do minus D or CMake CXS flags is it there? And, then you can have a profile that you use to invoke CMake, but that should be external I don’t think you should store inside your CMake list flags that define the ABI, the binary compatibility because, of course, two libraries will have their own set of flags, and they will disagree And, it won’t work It should be possible, it should take something external, some external input to know what kind of runtime, or what kind of minus STD it should be compiled with It should just make checks Okay is it possible with the environment you supply me to build or not and fail if you cannot But, not try to hijack the process and decide that you will change the way it was supposed to be built – [Audience Member] So the external library itself builds fine, and we built that with their own flags But, since we did find package on that, I think the flags leaked into our build – That could be this if some public flags are like, I don’t know, some minus D That’s what I said when I said do not set compile flags in targets For me compile flags that are very platform and infrastructure, it belongs to a profile that should be shared by every CMake project you build in the same environment You should not keep that inside CMake I think it’s a bad idea You’re just setting up yourself for disaster – [Audience Member] Okay, thank you – [Audience Member] Hi, so could you go back to your example of using Boost through the target? – [Mathieu] Yep – [Audience Member] So I own an Open Source library – [Mathieu] I think I can, yeah there is one here – [Audience Member] Perfect, right So I own an Open Source library, and I recently wanted to upgrade to use modern CMake So I switched to using the targets created by the find Boost script that comes in the box with CMake Then I updated my Boost version to the latest Boost version the day after it came out And, then my library didn’t work anymore because CMake refused to generate targets for the latest Boost because my belief is that it is because it doesn’t know the dependency information between the Boost libraries, and so it doesn’t feel confident in creating all of the targets because it doesn’t know the relationship between them And, then I have to wait for another update for CMake to come out in order to correct that But, of course that means that I have a two week delay where no one can use my library However, if I simply directly use the old variables again, it works fine Are you aware of anything that they are doing to address this problem? – That’s something that’s completely tied to the fact that the CMake provides the finder for you, and it’s decoupled from the version of Boost They provide that as a convenience because at the time where the other packages did not So I think it’s more of a convenience thing,

but that comes with the risk that any convenient finder that’s given by CMake will not be in line with the latest version of the package – [Audience Member] So you would not recommend me do this than? – Well that depends If Boost could provide the finder, I would say use that I’m not sure they do today because they use their own build system – [Audience Member] They do not – So that’s a tough choice I will agree Then again I’ve started working with the guy at Conan because I really believe that package management is the way to solve all that mess – [Audience Member] Okay, thank you – [Audience Member] Hey I’m pretty new to CMake, so this might be a really dumb question But, if you are writing a simple application, you depend on lib A, you depend on lib B, and both of them depend privately on Boost And, like Boost has three different ways you can build it into your project which component then my app, or lib A, or lib B is responsible, who owns that decision of how are you compiling the library in Or, does that depend I guess on how your finder is implemented – Okay, technically speaking, I would recommend you to run the find at the top level of your CMake list to make sure that you find only one version of every third party’s If you start splitting the finders, you will have two problems First, you might not require the same version, and you might have like a diamond issue with two different version like it was just shown in this morning’s talk The second problem you will have is performance You will not see it with two libraries, but where I come from, we had, at some point, a huge code base with CMake And, if everybody in each library like three or four level down is doing find, you’re wasting lots of effort especially because if you use some macros like project CMake will not catch the result So it will scan the file system like 1,000,000 times just to find the same library So yeah, my recommendation is find at top level all the third parties to make sure that everybody agrees on what you use – [Audience Member] Okay so ideally the libs that you depend on, all they’re saying is find package Boost, and the responsibility of how you find it and which one you’re– – Yeah you can tell CMake when you do a find to require minimum version It’s possible And, then it will fail if it’s not found – [Audience Member] Okay, thanks – Great, thanks everyone (audience clapping)