Global compiler variables
Working as a developer on a project which relies on 3rd party libraries involves a lot of unnecessary repetitive tasks, such as setting up build variables according to the local filesystem layout. In the case of project files, care must be taken to not accidentially commit a locally modified copy. If one does not pay attention, this can happen easily for example after changing a build flag to make a release build.
The concept of global compiler variables is an unique new solution for Code::Blocks which addresses this problem. Global compiler variables allow you to set up a project once, and any number of developers using any number of different filesystem layouts will be able to compile and develop the project. No local layout information ever needs to be changed more than once.
Names and Members
Global compiler variables in Code::Blocks are discriminated from per-project variables by a leading hash sign. Global compiler variables are structured; every variable consists of a name and an optional member. Names are freely definable, while some of the members are built into the IDE. Although you can choose anything for a variable name in principle, it is advisable to pick a known identifier for common packages. This way, the amount of information that the user needs to provide is minimised. The Code::Blocks team provides a list of recommended variables for known packages.
The member base resolves to the same value as the variable name uses without a member (alias).
The members include and lib are by default aliases for base/include and base/lib, respectively. However, a user can redefine them if another setup is desired.
It is generally recommended to use the syntax $(#variable.include) instead of $(#variable)/include, as it provides additional flexibility and is otherwise exactly identical in functionality (see mini tutorial).
The members cflags and lflags are empty by default and can be used to provide the ability to feed the same consistent set of compiler/linker flags to all builds on one machine. Beginning with revision 2664 (4 July 2006), Code::Blocks allows you to define custom variable members in addition to the builtin ones.
- Both set and global compiler variable names may not be empty, must not contain white space, must start with a letter and must consist of alphanumeric characters. Cyrillic or Chinese letters are not alphanumeric characters.
If Code::Blocks is given invalid character sequences as name, it may replace them without asking.
- Every variable requires its base to be defined. Everything else is optional, but the base is absolutely mandatory. If you don't define a variable's base, it will not be saved (no matter what other fields you have defined).
- You may not define a custom member that has the same name as a builtin member. Currently, the custom member will overwrite the builtin member, but in general, the behaviour for this case is undefined. If 'libext' is a custom member we can only write $(#variable.libext) and not $(#variable)/libext.
- Variable and member values may contain arbitrary character sequences, subject to the following three constraints:
- You may not define a variable by a value that references the same variable or any of its members
- You may not define a member by a value that references the same member
- You may not define a member or variable by a value that references the same variable or member through a cyclic dependency.
Code::Blocks will detect the most obvious cases of recursive definitions (which may happen by accident), but it will not perform an excessive depth analysis of every possible abuse. If you enter crap, then crap is what you will get, you have been warned.
defining wx.include as $(#wx)/include is redundant, but perfectly legal
defining wx.include as $(#wx.include) is illegal and will be detected by Code::Blocks
defining wx.include as $(#cb.lib) which again is defined as $(#wx.include) will create an infinite loop
Using Global Compiler Variables
All you need to do to start using global compiler variables is to put them in your project! Yes, it is really that easy.
When the IDE detects the presence of an unknown global variable, it will prompt you to enter its value. The value will be saved in your settings, so you never need to enter the information twice.
If you need to modify or delete a variable at a later time, you can do so from the settings menu.
The above image shows both per-procect and global variables. WX_CFG is defined in the project, but WX is a global user variable.
Sometimes, you want to use different versions of the same library, or you develop two branches of the same program. Although it is still possible to get around with a global compiler variable, it can become tedious. For this purpose, Code::Blocks supports variable sets. A variable set is an independent collection of variables identified by a name (set names have the same constraints as variable names).
If you wish to switch to a different set of variables, you simply select a different set from the menu. Different sets are not required to have the same variables, and identical variables in different sets are not required to have the same values, or even the same custom members.
Another positive thing about sets is that if you have a dozen variables and you want to have a new set with one of these variables pointing to a different location, you are not required to re-enter all this redundant data again. You can simply create a clone of your current set, this will duplicate all of your variables.
Deleting a set also deletes all variables in that set (but not in another set). The "default" set is always present and cannot be deleted.
Custom Members Mini-Tutorial
As stated above, writing $(#var.include) and $(#var)/include is exactly the same thing by default. So why would you want to write something as unintuitive as $(#var.include)?
Let's take a standard Boost installation under Windows as an example. Generally, you would expect a fictional package ACME to have its include files under ACME/include and its libraries under ACME/lib. Optionally, it might place its headers into yet another subfolder called acme. Thus, after adding the correct paths to the compiler and linker options, you would expect to #include <acme/acme.h> and link to libacme.a (or whatever it happens to be).
Boost, however, installs headers into C:\Boost\include\boost-1_33_1\boost and its libraries under C:\Boost\lib by default. It seems impossible to get this under one hood without having to adjust everything on every new PC, especially if you have to work under Linux or some other OS, too.
This is where the true power of global user variables is unveiled. When defining the value of the #boost variable, you go one step further than usual. You define the member include as C:\Boost\include\boost-1_33_1\boost and the member lib as C:\Boost\lib, respectively. Your projects using $(#boost.include) and $(#boost.lib) will magically work on every PC without any modifications. You don't need to know why, you don't want to know why.