Gwbuild-Tutorial2 - Simple App And Library¶
- Inhaltsverzeichnis
- Gwbuild-Tutorial2 - Simple App And Library
For this tutorial we extend the build files from the first tutorial (Gwbuild-Tutorial1). Here we will only discuss those build file sections not used in tutorial 1.
This example assumes the following folder structure:
- 0BUILD (top level build file)
- src/
- 0BUILD
- app/
- 0BUILD
- main.c
- lib/
- 0BUILD
- hellolib.c
- hellolib.h
Those files and folder are discussed in the following chapters.
Toplevel 0BUILD File¶
<?xml?>
<gwbuild requiredVersion="5.6.0" >
<project name="HelloWorld" version="0.9.134-beta" so_current="0" so_age="0" so_revision="1" write_config_h="TRUE">
<setVar name="package">$(project_name)</setVar>
<define name="PACKAGE" value="$(package)" quoted="TRUE" />
<!-- prefix handling -->
<option id="prefix" type="string">
<default>/usr/local</default>
</option>
<setVar name="prefix">$(option_prefix)</setVar>
<setVar name="bindir">$(option_prefix)/bin</setVar>
<setVar name="libdir">$(option_prefix)/lib</setVar>
<setVar name="includedir">$(option_prefix)/include</setVar>
<setVar name="pkglibdir">$(libdir)/$(package)</setVar>
<setVar name="pkgincludedir">$(includedir)/$(package)</setVar>
<setVar name="pkgdatadir">$(datadir)/$(package)</setVar>
<!-- system -->
<ifVarMatches name="GWBUILD_SYSTEM" value="windows" > <!-- long version of IF statement with THEN and ELSE -->
<then>
<define name="OS_WIN32" value="1" />
<setVar name="hw_sys_is_windows">1</setVar>
</then>
<else>
<define name="OS_POSIX" value="1" />
<setVar name="hw_sys_is_windows">0</setVar>
</else>
</ifVarMatches>
<define name="HW_SYS_IS_WINDOWS" value="$(hw_sys_is_windows)" />
<!-- dependencies ( pkg-config and libs) -->
<dependencies>
<dep id="gwenhywfar" name="gwenhywfar" minversion="5.5.1.1" required="TRUE" />
<dep id="aqdatabase" name="aqdatabase" required="TRUE">
<variables>aqdatabase_typemakerdir</variables>
</dep>
</dependencies>
<!-- symbol visibility -->
<checkCompiler>
<arg name="has_symbol_visibility">-fvisibility=hidden</arg>
</checkCompiler>
<ifVarMatches name="has_symbol_visibility" value="TRUE" >
<setVar name="visibility_cflags">-fvisibility=hidden</setVar>
<define name="GCC_WITH_VISIBILITY_ATTRIBUTE" />
</ifVarMatches>
<checkheaders>
locale.h libintl.h iconv.h
</checkheaders>
<checkfunctions type="c" >
snprintf
</checkfunctions>
<define name="OS_TYPE" value="$(GWBUILD_SYSTEM)" quoted="TRUE" />
<define name="OS_SHORTNAME" value="$(GWBUILD_SYSTEM)" quoted="TRUE" />
<subdirs>
src
</subdirs>
</project>
</gwbuild>
Predefined Variables, If-Then-Else-Clause¶
This chapter introduces some predefined variables and if-then-else constructs (long form with then and else).
<ifVarMatches name="GWBUILD_SYSTEM" value="windows" >
<then>
<define name="OS_WIN32" value="1" />
<setVar name="hw_sys_is_windows">1</setVar>
</then>
<else>
<define name="OS_POSIX" value="1" />
<setVar name="hw_sys_is_windows">0</setVar>
</else>
</ifVarMatches>
<define name="HW_SYS_IS_WINDOWS" value="$(hw_sys_is_windows)" />
Here we see the predefined variable GWBUILD_SYSTEM which contains the type of the system:
- posix (Linux, BSD etc.)
- windows
In this build file fragment we set the value of a define and a variable according to the target system.
Other pre-defined variables are listed below.
Build System¶
- GWBUILD_SYSTEM: Operating system (linux, windows, osx, solaris, freebsd, openbsd, hpux, tru64, irix, aix)
- GWBUILD_SYSTEMTYPE (windows, posix)
- GWBUILD_ARCH (x86_64, x86_32)
- GWBUILD_LIBTYPE (sharedlib, staticlib)
Project Info¶
This information is derived from the attributes given to the <project> element in the main 0BUILD file.- project_name
- project_version
- project_vmajor
- project_vminor
- project_vpatchlevel
- project_vbuild
- project_vtag
- project_so_current
- project_so_age
- project_so_revision
- project_so_effective
- VERSION
- PACKAGE
Build/Source Tree Information¶
- topbuilddir
- topsrcdir
- builddir
- srcdir
- ifVarMatches: check whether a variable matches a given pattern (wildcards like * and ? allowed)
- ifNotVarMatches: check whether a variable does not match a given pattern (wildcards like * and ? allowed)
Check Compiler Characteristics, If-Clause¶
In this case we check for a special compiler-characteristic called symbol-visibility. This is used to define which functions and variables especially from libraries are to be exported. It is a feature of GCC and other compilers. There are different visibility modes (see http://gcc.gnu.org/wiki/Visibility), the most important ones:- hidden: symbols not explicitly exported are hidden to the outside
- default: symbols are generally exported unless specified otherwise
<checkCompiler>
<arg name="has_symbol_visibility">-fvisibility=hidden</arg>
</checkCompiler>
<ifVarMatches name="has_symbol_visibility" value="TRUE" >
<setVar name="visibility_cflags">-fvisibility=hidden</setVar>
<define name="GCC_WITH_VISIBILITY_ATTRIBUTE" />
</ifVarMatches>
The XML element <checkCompiler> tries to test-compile a small test file using the given compiler arguments and sets the given variable accordingly.
In this case we check for -fvisibility=hidden and assign the result to the variable has_symbol_visibility. If the test-compile works the variable is assigned the value "TRUE", otherwise "FALSE".
Also please note that here the short version of <ifVarMatches> is used (without THEN and ELSE elements).
Include Build Files from Subdirs¶
This XML element makes gwbuild look into the given subfolders and read their 0BUILD files as if they where at the current position inside this 0BUILD file.
<subdirs>
src
</subdirs>
src/0BUILD File¶
This only contains instructions to include 0BUILD files from more subfolders.
<?xml?>
<gwbuild>
<subdirs>
lib
app
</subdirs>
</gwbuild>
src/lib/0BUILD File¶
This contains the definition of a target which creates an installable library.
<?xml?>
<gwbuild>
<target type="InstallLibrary" name="hellolib"
so_current="$(project_so_current)"
so_age="$(project_so_age)"
so_revision="$(project_so_revision)"
install="$(libdir)" >
<includes type="c" >
$(gwenhywfar_cflags)
$(aqdatabase_cflags)
-I$(topsrcdir)/src/lib
-I$(topbuilddir)/src/lib
-I$(topbuilddir)
-I$(topsrcdir)
-I$(srcdir)
</includes>
<includes type="tm2" >
--include=$(aqdatabase_AQDATABASE_TYPEMAKERDIR)/c
--include=$(srcdir)
--include=$(builddir)
</includes>
<define name="BUILDING_HELLOWORLDLIB" />
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<headers dist="true" install="$(includedir)" >
hellolib.h
</headers>
<sources>
hellolib.c
testtype.xml
</sources>
<libraries>
$(gwenhywfar_libs)
$(aqdatabase_libs)
</libraries>
</target>
</gwbuild>
InstallLibrary Target¶
This target is an installable library, usually a shared library (extension .so on Linux or .dll on Windows).
At least on Linux a library has a library-version which allows to install libraries in multiple versions on a system. This library-version (also called so-version) can be given as attributes to the <target> element.
To make things easier we here just use the library version we provided to the <project> element in the toplevel 0BUILD file. Here we also specify that the created library is to be installed to libdir which we defined in the toplevel 0BUILD file.
It is generally a good idea to define global variables and defines in the toplevel 0BUILD file so that you always have important global definitions in one place.
<target type="InstallLibrary" name="hellolib"
so_current="$(project_so_current)"
so_age="$(project_so_age)"
so_revision="$(project_so_revision)"
install="$(libdir)" >
Include Typemaker2 Files¶
When generating source files from XML files with typemaker2 sometimes type definition files from other projects are needed. With a include element for typemaker2 search paths can be added:
<includes type="tm2" >
--include=$(aqdatabase_AQDATABASE_TYPEMAKERDIR)/c
--include=$(srcdir)
--include=$(builddir)
</includes>
Here we add typemaker2 XML folders from the AqDatabase project and also from different paths inside this project. Note that the attribute type is set to "*tm2*" instead of "*c*".
<define> Inside a <target> Element¶
Defines inside a target element are only valid inside that specific target. They are conveyed to the compiler via a -D argument on the command line.
<define name="BUILDING_HELLOWORLDLIB" />
This element adds a -DBUILDING_HELLOWORLDLIB to the compiler argument list.
Using GCC's Visibility Feature, Local Variables, CFLAGS¶
<setVar name="local/cflags">$(visibility_cflags)</setVar>
See above for a description of the visibility feature. What's important here is that we use local variables.
Normally variables defined in any 0BUILD file of a project are available to all 0BUILD lines in any file after the <setVar> statement. However, this is not always wanted. E.g. in some folders we might want to use different compiler options, maybe not all code is ported to using the GCC visibility feature etc.
This is where local variables come into play: Variables whose name start with "*local/*" are only valid within the current folder, outside the current folder those variables don't even exist (unless declared there as well, to their own local value).
In addition, we use the local variable named cflags which contains some command line arguments passed to the compiler (e.g. optimizations like -O3, debug options like -ggdb etc.).
Sources¶
We already know the <sources> element from the previous tutorial. However, this example demonstrates how typemaker2 files can be used.
<sources>
hellolib.c
testtype.xml
</sources>
As can be seen here source files for typemaker2 can simply be added to the list of source files. gwbuild recognizes those files and knows that it has to call typemaker2 to create C-files from the XML file.
The beauty of the integration of typemaker2 into the build process is that gwbuild will rebuild the source files automatically if needed. Because of this gwbuild is especially suited to compile and link projects directly from within a git folder without having to write into the source tree.
Using Libraries and Dependencies¶
In the previous tutorial we learned how to specify dependencies, i.e. libraries to link against. In this case those libraries aren't really needed, but for demonstration purposes we include them anyway:
<libraries>
$(gwenhywfar_libs)
$(aqdatabase_libs)
</libraries>
Remember, in the first tutorial we learned that the <dep> element creates some variables like gwenhywfar_CFLAGS and gwenhywfar_LIBS. We simply add them here into the libraries section (variable names are case-insensitive).
src/app/0BUILD File¶
This contains the definition of a target which creates an executable whcih also uses other targets from this project (e.g. the hellolib from src/lib).
This file doesn't look very different from the other build files.
<?xml?>
<gwbuild>
<target type="Program" name="helloworld"
install="$(bindir)" >
<includes type="c" >
$(aqdatabase_cflags)
-I$(topsrcdir)/src/lib
-I$(topbuilddir)/src/lib
-I$(topbuilddir)
-I$(topsrcdir)
-I$(srcdir)
</includes>
<includes type="tm2" >
--include=$(builddir)
--include=$(srcdir)
</includes>
<setVar name="local/cflags">$(visibility_cflags)</setVar>
<sources>
main.c
</sources>
<useTargets>
hellolib
</useTargets>
</target>
</gwbuild>
Using Other Targets From This Project¶
This application uses the library hellolib from the target defined in the 0BUILD file in src/lib.
<useTargets>
hellolib
</useTargets>
You only have to add the name of the target (as given to its <target> definition). gwbuild will figure out what that target is and how it is combined with the current target.
In this case hellolib in an installable (shared) library so the application in this target will link against that library.
Advanced Usage¶
See Gwbuild-advanced for advanced usage of Gwbuild.