tag:blogger.com,1999:blog-47583609777839179222024-03-13T23:12:54.526-07:00Between Man & Machinelugia584http://www.blogger.com/profile/00022029005116311622noreply@blogger.comBlogger4125tag:blogger.com,1999:blog-4758360977783917922.post-29979570052834998782018-01-18T03:30:00.000-08:002018-01-18T03:30:17.792-08:00Summer Adventure 2018: Learning CMake #2It has been two days since my last wrestle with CMake. In this time I continued to play around with the build system and test my various hypotheses about the way the system works. To provide at least the minimal structure necessary to articulate the experience, from henceforth I will try to recount and explain what I did in the order I did it in.<br />
<br />
<b>Built-In Variables</b><br />
<b><br /></b>
I wanted to test if my theory on how the setting of various global, provided variables affected the build chain (variables such as PROJECT_SOURCE_DIR, CMAKE_BINARY_DIR, etc). To that end I had a generated header file define the various variables as macros and my C++ printed these out. My theory was correct in that setting these variables changed as I predicted them to. However, I came to realise these variables, with the exception of output directories like CMAKE_RUNTIME_OUTPUT_DIR and CMAKE_ARCHIVE_OUTPUT_DIR, are intended to be used read-only and changing them once CMake has begun has no effect. It made sense to me people were using 'binary' interchangeably with 'build' which in retrospect makes sense since all compiled code goes into the build/binary directory, but before I had realised this I was accustomed to using 'binary' solely for executables and not for midway compiled and object code.<br />
<br />
<b>(Static) Libraries</b><br />
<b><br /></b>
The next thing on my list of to explore was the creation of libraries. the <i>add_library()</i> command is used for naming a target (which will become the library) and using a library type like STATIC, and the source files which comprise that library. To test this out I made a static library out of a single 'greeting' function and successfully linked it in with my program. This further reinforced my intuition of what <i>add_subdirectory()</i> did. This command is used as sort of and <i>in-build </i>subdirectory additive instead of adding external projects with <i>ExternalProject_Add. </i>By this I mean when you need to build subdirectories which are logically part of the main project instead of being 3rd-party <i>add_subdirectory()</i> is used.<br />
<br />
<b>ExternalProject_Add</b><br />
<b><br /></b>
The way I had hoped to have my build system work was that all external libraries were built once only and installed the first time, instead of having them be rescanned and possibly rebuilt as would have happened if <i>add_subdirectory()</i> was used. This served as the motivation into using <i>ExternalProject_Add()</i>. Once the module was <i>include(ExternalProject)</i>'d into my top-level CMakeLists.txt file, I got to explore its customisation options which are incredibly flexible and offer far more customisation options than the average user needs. You can tailor everything from downloading from VCS like Git or using local copies to configuring the project, to patching, building, installing, testing...and more! You can actually add more steps which is incredible. For my purposes however I only wanted to change the configure stage, so I defined the SOURCE_DIR and BINARY_DIR to my directory's extern and extern/build folders. I also passed in a custom CMAKE_INSTALL_PREFIX so that when CMake installed the external project (which I set up as a library) it put in my project/lib directory - very nice.<br />
<br />
<b>install</b><br />
<b><br /></b>
While I was messing around with <i>ExternalProject_Add()'</i>s install options I also learnt about the install target that CMake let's you use. I learnt CMake, again, has got you covered as you can install individual targets into distinct locations, install all the different types of libraries into their own directories too using commands like <i>install(TARGETS <target> ARCHIVE DESTINATION <dest>)</i>, or instead of archive, library, module, etc. You can also install whole directories! That doesn't seem to grand but the realisation of its convenience of moving headers from the source tree into easier-to-access locations it makes organising the project for an orderly person like myself very simple. Directories, similar to the rest of the <i>install()</i> family, are installed like <i>install(DIRECTORY <dir> DESTINATION <dest>)</i>.<br />
I should point out that install is very, very flexible with external projects and you can do things like import various exported targets from external projects (the import/export is actually more elaborate, but I didn't go that far) and install them to desired places. I only lightly dabbled in this to begin with.<br />
<br />
<b>Variables</b><br />
<b><br /></b>
It was only a small discovery and since CMake's syntax is your run-of-the-mill scripting language, I figured that variables get interpolated as strings and so you can say something like "USE_${VAR}" and the result will be "USE_FOO", assuming of course VAR held the value of "FOO", but you get the idea. Similar to recursive structures in functional languages you can also build up a list of strings and store it into a variable (even into itself!) with something like <i>set(VAR ${VAR} arg1 arg2...)</i>. Even when you use VAR for the first time it defaults to the empty string so this always works.<br />
<br />
<b>Control Structures</b><br />
<b><br /></b>
The last tool I needed to start my rudimentary build system was basic conditional and looping structures. Unsurprisingly CMake has <i>if()</i> where a boolean variable is tested to see if it's true (or non-empty I think?), <i>foreach()</i> for iterating over a list with a loop variable, and functions too. These were very easy to pick up as it was near identical to all other imperative languages which have these constructs, so not much to say here.<br />
<br />
With the bare minimum knowledge of all of these topics under my belt I was actually able to write a CMakeLists.txt file which fit my needs! In a future post I'll detail what my plan is in relation to learning OpenGL and what I will put this build-system to use for.<br />
<b><br /></b>lugia584http://www.blogger.com/profile/00022029005116311622noreply@blogger.com0tag:blogger.com,1999:blog-4758360977783917922.post-73146429242141824572018-01-16T04:11:00.001-08:002018-01-16T04:14:12.104-08:00Summer Adventure 2018: Learning CMake #1In software development, we follow a simple pattern. Find zero or more external libraries to make life easier; write our own custom code; compile/interpret/link everything together to make a complete application. Everything else we do is a variant of this pattern (construction-wise), and it <i>prima facie</i> it appears extremely easy for someone to just come in and pick up. But as with most things worth doing, the devil is in the details. First a language must be chosen, compiler/interpreter flags used appropriately, directory structure intuitive, etc. Build systems simplify this, but there is always a learning curve associated with how complex that system should be. CMake has been no different. CMake is a common build system that allows for configuration of a build system to a specific platform, and it generates the native build files which are then built with usually Makefiles on *nix, and a Visual Studio solution on Windows. As a complete novice to this ecosystem of software, I dove into the CMake authors' own tutorial <a href="https://cmake.org/cmake-tutorial/">here</a>.<br />
The first thing I had to grasp is CMake tracks two different tree structures: a source-tree that tracks the source code of your application, and a build tree where compiled code goes. If the trees occupy different directory structures then it is called an <i style="font-weight: bold;">out-of-place</i> build, else it is an <i style="font-weight: bold;">in-place-build</i>. Since I hate clutter in my projects I always do out-of-place builds. My first line of inquiry was into how these trees are built. The answer lies in the CMakeLists.txt files you place, first at the root, and the in subdirectories as the project. In a CMakeLists.txt file any time you use <i>add_subdirectory()</i>, the subdirectory must contain one of the .txt files and then that forms the link in the tree. By default it would seem the CMake variables *_SOURCE_DIR and *_BINARY_DIR default to the directory the CMakeLists.txt file is. For instance, the PROJECT_SOURCE_DIR is set to the directory the most recent <i>project()</i> has been used, CMAKE_BINARY_DIR is set to the directory that CMake was ran in and if not used out-of-place then it is the same as CMAKE_SOURCE_DIR. The most poignant fact is that CMAKE_CURRENT_SOURCE_DIR is always the directory of wherever the current CMakeLists.txt is being processed. So the flow is cmake begins with the root .txt file, and when it encounter <i>add_subdirectory</i> is goes onto that node in the tree and processes it, setting the appropriate variables as it travels. <a href="http://johnnado.com/cmake-directory-variables/">This post</a> explains this more in depth, since I know I'm just spewing my thoughts rather incoherently.<br />
This was a major understanding for me as all the examples I had looked at used these variables seemingly interchangeably and it was very confusing. When it comes time to organise directory hierarchies making sure that I use the correct variable is invaluable.<br />
The last thing I followed on this day was that you can define your own and global variables using the <i>set()</i> command. Leaving aside the global variables, by defining your own variables you can use them in conditional logic in the various CMakeLists.txt files, but you can also auto-generate header files that have been templated and cmake interpolates these variables into placeholders in the header templates. Very useful.<br />
<br />
I want to confirm my theory about the the various DIR variables, so I am going to use this header interpolation to print out the variable names in a C++ program. One of the many nuances of computing is that we can play and muck around when exploring and no-one gets hurt!<br />
<br />
Till then.<br />
<br />lugia584http://www.blogger.com/profile/00022029005116311622noreply@blogger.com0tag:blogger.com,1999:blog-4758360977783917922.post-40509817316559849782018-01-16T03:43:00.001-08:002018-01-16T04:11:59.449-08:00Summer Adventure 2018: Prelude To OpenGL 4.5 & CMakeIn Semester 2 2016 (which for us Australians is from August to November) I took an undergraduate course in computer graphics at the University of New South Wales (UNSW), Sydney. I've always been fascinated by video games, which necessarily involve computer graphics (why else is 'video' in the phrase?), and so to me this felt like an obvious course to take. In the course we learnt about various concepts in CG, and to punctuate what we were learning we had two assignments in OpenGL. The rub however was that we were using old JOGL (Java bindings for OpenGL) bindings and so the version of OpenGL was also old - core version 3.x (I don't remember exactly which version). Modern OpenGL (as of writing) is at 4.6 so clearly if I want to carry over that knowledge to the future I'm going to need to get used to the modern library. Personally, my language of choice is C++ because despite its oft times crazy, overwhelming (to those uninitiated) syntax it is fast, and also offers as good as abstraction as languages like Java, and probably Python. Python makes me feel like an idiot when I use it because everything is so far from the computer it's like I'm not sure how efficient the code I write is. That aside, C++ is my sweetheart.<br />
In JOGL alot was done behind the scenes and one could get into writing rendering code almost immediately. OpenGL for C++ is not at all like that; C++ has no standard windowing toolkit (libraries like Qt are used by they aren't always standards compliant), and the OpenGL functionality is loaded, at runtime, from whatever graphics driver is being used. To complicate matters further, there is no canonical tutorial on how to get those setup AND there is more than one windowing toolkit and extension loader for OpenGL, some defunct, others apparently not being flexible enough. This was my first hurdle to overcome - how the hell to set things up.<br />
At UNSW there was never a course about so-called 'boilerplate' setup such as an in-depth look into a build system, or how production code is written, packaged, and exported. There was one course, COMP2041, called 'Software Design & Construction' but it was more a joke than a practical intro into these matters. So I began to scour various wikis and online tutorials (which by the way are all outdated) about how to set these things up.<br />
I eventually settled on using GLFW as the window toolkit mostly because the website documentation is readable. And since GLFW recommended using GLAD as the extension loader, I settled on that too for my linux box. Now GLFW source is built using CMake. I had heard of Cmake before but never actually touched it. It was at this point I decided in a joint project I would dabble in using CMake as a proper build system, and in learning the modern OpenGL. Or at least as modern as I can get it, the latest version of the OpenGL Super Bible uses OpenGL 4.5, so that's what Im going for. My IDE on Linux for C++ is CLion (because educational license ;) ) and on Windows I use Visual Studio (like everyone...). Upon starting my new project I was face-to-face with my first CMakeLists.txt. And so the adventure down the rabbit hole began.lugia584http://www.blogger.com/profile/00022029005116311622noreply@blogger.com0tag:blogger.com,1999:blog-4758360977783917922.post-60600222955000745352018-01-16T03:24:00.001-08:002018-01-18T03:32:41.643-08:00IntroductionMy name is Simon Haddad, and I am a programmer, musician, and seeker of knowledge. Among these things I am also an regular viewer of Dr. Jordan Peterson. He often encourages people to write to formulate your own ideas. Because I (possibly) like the environment and would rather not write on paper, which among many things is not accessible globally from any wifi-enabled device, I am writing in this blog which I'm expecting only I will read. What am I writing about however? Since I like to learn things (when not too difficult), and since university beat the academic crap out of me, I have since learned that when I set out to master a new skill, writing, summarising, theorising, and opining about the topic in question helps me to formulate my ideas better, and articulate to the subject, and to myself, things I would have never considered otherwise. This blog will henceforth be the spewing out of my various mental utterances, as I explore around whatever intellectual/physical domain I happen to be interested at the time. That means this blog will be more like a diary then any tutorial or how-to guide on what I explore. There is a good chance that when and if I get proficient in the use of what I learn then I will write a proper guide or tutorial, especially if I feel like there isn't already a good one available.<br />
<br />
Anchors away!lugia584http://www.blogger.com/profile/00022029005116311622noreply@blogger.com0