<div class="gmail_quote">On Wed, Mar 4, 2009 at 3:59 PM, Michael Wild <span dir="ltr"><<a href="mailto:themiwi@gmail.com">themiwi@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im"><br>
On 4. Mar, 2009, at 20:58, Robert Dailey wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Is CMake not general-purpose as well?<br>
</blockquote>
<br></div>
No, it's not. It's neither a system programing language nor would you consider it for anything else than creating a build system.</blockquote><div><br>But even domain-specific programming languages, like CMake, can benefit from some language features that are in a general purpose language. The domain in which the language lies is not important. Whether I'm coding in CMake or C++, I need my tools to make my job as easy as possible. I'm human, I make mistakes, I expect my tools to find as many of those mistakes as possible. Granted, tools can't find all of the problems, but there are problems it can find ahead of time and to deliberately not implement that time-saving functionality is wrong.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im">
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I'm not asking CMake to become C++,<br>
however there are some common language features that are useful.<br>
</blockquote>
<br></div>
I don't claim that your proposal is not useful, I just don't see that it would add enough value to justify the effort.</blockquote><div><br>It saves people frustration and debugging. You will also evolve as a human being.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im">
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Note that<br>
there are already concepts in CMake that respect directory scope. There are<br>
properties specific to directories, for example. Another example is<br>
include_directories(). Include directories added by a parent are available<br>
to children and children can append to this list, however siblings do not<br>
inherit each others' include directories.<br>
</blockquote>
<br></div>
That's because in these cases name-scope is absolutely crucial for the correctness of the build. They directly affect the generated build system and the resulting compiler/tools-invocations. The same is not true with the scope of macro/function names.</blockquote>
<div><br>Mistakenly calling a macro which is defined in a location intended not to be accessible to parent directories also affects the generated build system. If I'm calling the wrong function, I'm potentially setting the wrong build options and depending on the severity of the issue it may go unnoticed.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im">
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
"Good enough" is relative. Each person has their own standards for "Good<br>
enough", so there is no one true path here that will make everyone happy.<br>
</blockquote>
<br></div>
"Good enough" as a programming concept means "does it do the job". There's always room for better design, more efficient implementation etc. But at the end of the day it has to fulfill the requirements, be useable and maintainable. As soon as it does the job reasonably, it can be considered "good enough". As you point out, what exactly "good enough" means is not always clear.</blockquote>
<div><br>What you are talking about is "functional". However, functional is not always acceptable nor is it always production worthy. A prototype of an airplane game can be considered "functional", however it is by no means acceptable as a production-quality application. Therefore, "Good enough" doesn't always cut it, and it sounds lazy.<br>
<br>If your job was to create a calculator app that does nothing more than divide 2 numbers, your definition of good enough would be to have the app take 2 arbitrary entities, perform division on it, and print the result. Doing it beyond functional would be to check if both of those entities are numbers. You would also check to see that you are not dividing by zero. In the former case, you would get a crash and the user would be confused as to what went wrong. The usability of the application is in jeopardy. However, in the latter you are more than just "functional", you are exceptional. The user can get detailed error dialogs explaining exactly what the problem is and how to fix it. This makes the lives of everyone who uses the calculator app better.<br>
<br>Fullfilling the requirements is something that CMake does indeed do (ignoring bugs), however by only doing the minimum required effort possible to make the application "Good enough" (functional), you compromise the usability of the software. What would take me less than 5 seconds to find with a human-readable error message in CMake ("ERROR: Using a function or macro that doesn't exist") quickly becomes a task that requires extensive debugging, effort, and time. The problem may even go unnoticed and my resulting build system may behave in erratic ways because the incorrect macro was being called due to simple programmer error (Maybe I forgot to replace a function call somewhere after an iteration of refactoring).<br>
<br>Human beings aren't perfect, and as programmers we often make silly mistakes. We create tools like CMake and the C++ compiler not not only provide some function, such as building an application or a build system, but to also make the process of doing so as effortless as possible. We also expect our tools to take some of the error-proneness out of fat-fingering things ourselves. The less responsibility the programmer has, usually the better off the process of development becomes.<br>
<br>There is absolutely no excuse whatsoever for the behavior I'm experiencing. Using the excuse that CMake is functional has nothing to do with this problem. The fact that you are defending this problem seems lazy to me. This issue makes CMake less usable and also makes refactoring a pain. You also compromise the maintainability of CMake scripts. I can have the best design in the world and make every effort to hide implementation details from other things that dont' care about it, but when you deliberately make everything globally accessible when I have no control over that behavior you make my code unmaintainable.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im">
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Code documentation does not prevent programmer error. It is error prone to<br>
have macros or functions available to the parent directory in which they<br>
were defined. What if I was going through and doing some refactoring and I<br>
renamed a macro somewhere and also put it a bit further down in the<br>
directory tree. Other places that call it will still work and CMake will not<br>
give me an error message.<br>
</blockquote>
<br></div>
If you are sloppy, such errors can occur. But on the other hand, please also consider that it can be very useful to have global macro/function names. I will give an example below.</blockquote><div><br>I'm not sloppy, I'm a human being. Programmer derives from the "Human Being" class. You aren't perfect, so why should CMake assume that? CMake is obviously putting responsibility on the programmer that is unnecessary. If we were all perfect, then "functional" would be an acceptable determination of a production worthy application. CMake should create me a build system, but also help me in any way possible to make performing that task as easy, effortless, and as non-error-prone as possible.<br>
<br>Iterative development is a common approach to software. This also applies to CMake. CMake is complex enough that the code can go stale. Requirements can change, just like they do in software. What if the directory structure for projects change? What if a project is removed or added? CMake will constantly change as the projects change, and with that you perform refactoring. We've all made the mistake of typing a number wrong, or hitting an extra key that we did not mean to. We've also all been victims of copy and paste errors. All of these errors are mistakes typical human beings make, since we are not perfect. CMake should make every effort to find these issues for us at the earliest point possible. When I forget to rename a function, I don't want CMake to accept that because it was defined at some leaf directory.<br>
<br>Given how most of the directory related properties work, the scope of macros and functions is inconsistent. It is a common assumption by many programmers that when I define a macro in CMake in a sub-directory that it will not be seen or be accessible by any parents.<br>
<br>Also, if you want global macros or functions, why not use include()? If you don't want to do that, find your root CMakeLists.txt and implement the macro or function there, and every single child directory in the entire hierarchy will inherit that particular function or macro and have complete access to it.<br>
<br>When you go the route of having every single function accessible in a global manner regardless of where it was defined, you quickly make CMake unreadable and unmaintainable. When I'm a new employee at a company and I'm trying to review the CMake build system to try to find what macros or functions I can call, I'm going to be forced to look at *all* CMake files in the entire hierarchy instead of going from parent to parent. It becomes extremely difficult to find all of the macros you can use when they are all scattered about and all globally accessible.<br>
<br>You also destroy the ability to create 2 macros with the same name. For example, suppose you have two macros named create_project(). Both will have completely different implementations. One is defined in c:\foo\project1 and the other in c:\foo\project2. I now have to arbitrarily give each of them different names when the same name for both would have been perfectly acceptable and reasonable.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Again, I do agree to a certain degree. However, it's impossible to prevent all errors.</blockquote><div><br>We're not talking about making CMake perfect. We're talking about making CMake solve problems we know can be solved. We know that it's wrong for macros, when defined, to become "globally accessible" regardless of directory depth. I've already established that it is error prone and I have given many examples to back it up. We know the problem can be solved, and the only reason we're having this discussion is because you feel it should not be solved because the only thing that matters is that CMake be "functional".<br>
</div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im">
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Again, this is "good enough" for *you*. Obviously not everyone will agree<br>
with your outlook on how CMake should work, and the same goes for my opinion<br>
on it. I also don't like the mentality most open source projects take of "If<br>
you don't like it, implement it yourself". I've actually implemented<br>
features that made sense in other open source projects before, only for<br>
their authors to arrogantly refuse to apply them because of their personal<br>
bias towards it being "good enough".<br>
</blockquote>
<br></div>
I understand the frustration, I know it. But then, you have to realize that it is ultimately the owners/maintainers of a project who decide what goes in and what not. Sometimes it is also difficult for them to keep their project on track and not have it evolve into a unmaintainable feature-monster. However, good news about open source projects is, that as a last resort you can still fork them...</blockquote>
<div><br>Yes it does get a bit frustrating sometimes. Open source projects right now are very black & white as far as feature requests go. You either have to become an active developer on the project to get features implemented, or you dont' get them implemented at all. In this case, I consider this issue a bug and not a feature. It's very hard to justify to people at times that a particular change makes sense and that when it is done it will benefit the community as a whole. I have a family, a job, and other things going on and have no time whatsoever to contribute to this project. If I could, I would. However, doing it myself doesn't help.<br>
<br>All developers have to agree that a particular feature or bug fix makes sense. If each developer has the "I'm going to do what I want to do" mentality, you end up creating crappy software. You all have to work as a team and carefully determine your requirements and what contracts you will fulfill. So even if I decided to implement this myself in CMake, you obviously would still have issues or disagreements with the bug fix. I don't see software development in such a selfish way. The whole reason for me discussing this issue with you guys is to not just ask you to do it for me, but to see if the community would find some use in it. If a majority of people agree that the current behavior is broken and could be fixed, then it should be fixed.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"><div class="im"><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
I think the best step to take in this case is to call a vote from the<br>
community. Let's see how many people would actually like to see child macros<br>
not available to their parent directories. I think this is a fundamental<br>
concept shared by many languages and makes perfect logical sense.<br>
<br>
A lot of times I organize projects with a common directory hierarchy in<br>
groups. For example, I may have projects structured like this:<br>
<br>
foo/components/A<br>
foo/components/B<br>
foo/components/C<br>
<br>
I can have the foo/components/CMakeLists.txt file define a macro called<br>
define_component(). This macro would take advantage of the fact that it<br>
knows a little bit about the hierarchical pattern of the directory structure<br>
for all component projects A, B, and C. However, this macro is completely<br>
useless in a directory called foo/libraries, for example.<br>
</blockquote>
<br></div>
Well, then I propose you call that macro A_define_component(). Using this naming scheme it becomes very clear what the intent and scope of this macro is. Using good and consistent naming conventions greatly help avoiding errors.</blockquote>
<div><br>No, that's not a naming convention, that's name mangling. It's arbitrary and foolish. The very fact that you've appended arbitrary suffixes/prefixes to the name implies that there is a fundamental need for a packaging concept, like namespaces. define_component() is a perfect name and is ambiguous to which specific component it is defining. This is the very essence of reusable code. define_component() is reusable, A_define_component() is not. There's no reason to have 1 macro per component as you suggest.<br>
<br></div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Now to the counter-example, where global macros are useful. Let's say that A is an application providing a plugin-architecture. B and C are plugins for A. To make things easier, foo/components/A/CMakeLists.txt defines a macro, say add_A_plugin(), allowing you to pass it some parameters, such as the name and the sources of the plugin. The macro then sets things up appropriately to create a plugin for A. With your approach one would be forced to define the macro either in foo/CMakeLists.txt or foo/components/CMakeLists.txt where it doesn't belong.<br>
<br>
I do know that the above example is a bit contrived and that such a macro probably should go into a AUse.cmake file. But still, I think one can see the usefulness of global macro/function names.</blockquote><div><br>The example is a bit hard to work with but here is the way I would do it:<br>
<br>I'd have the following structure:<br>foo/A<br>foo/A/plugins/B<br>foo/A/plugins/C<br><br>I would define the add_plugin() macro into foo/A/CMakeLists.txt and call that macro from projects B and C (they both would have CMakeLists.txt files). None of this requires any global macros and both B and C inherit the macro.<br>
<br>I fail to see a need for global macros as you explain them. As I said before, if you want global macros you have 2 choices. You can either use includes or define the macro at the root CMakeLists.txt file.<br> </div><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div class="im">
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Having said that, why should the macro defined in<br>
foo/components/CMakeLists.txt be in any way accessible in<br>
foo/libraries/CMakeLists.txt? It is error prone and causes suble bugs in<br>
CMake that can take a long time to track down.<br>
</blockquote>
<br></div>
As I said above, if foo/components/CMakeLists.txt provides some macros which other parts of the build system should use, it is very useful.</blockquote><div><br>The problem is that foo/components/CMakeLists.txt would *not* define any macros useful to other parts of the build system above itself. It is only useful to its own sub-tree. If you are defining macros in such a way you are doing something evil and CMake is allowing it. If I had something so useful on such a global scale as that, I would most certainly either use include() or define that macro in the highest directory as necessary (up to the root CMakeLists.txt file).<br>
<br></div></div><br>