Skip to content

Commit

Permalink
Add subproject example.
Browse files Browse the repository at this point in the history
Added example how to structure projects with libraries as subprojects
were the library also can have their own example and/or unittests.
  • Loading branch information
questor/Inter authored and deplinenoise committed Aug 30, 2014
1 parent d4b89cd commit 3fdd5e0
Show file tree
Hide file tree
Showing 10 changed files with 383 additions and 0 deletions.
205 changes: 205 additions & 0 deletions examples/subproject-organization/README.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@

How to setup projects with subprojects
======================================

This example demonstrate how to have libs with their own examples and/or
unit-tests which are compilable directly in their root folder or only the
library as part of a bigger project. the idea is to have the libraries as
subprojects included into the main-app (also revision-control wise).

you can compile this example in this main-folder (and get the main-app)
or you can start tundra in extlibs/libA and get the library-example-app.


== the basic setup

this example application structure looks like that:

-------------------------------------------------------------------------------
app-root (folder)
|- extlibs (folder)
| |- lib1 (folder)
| | |- subfolders of lib1
| | |- sources of lib1
| |
| |- lib2 (folder)
|
|- sourcefiles for app
-------------------------------------------------------------------------------

the main-app consists of sourcefiles and one extra folder called "extlibs" with
subrepositories (buildsystem-wise as well as rvc-wise). these libraries can contain
example- and/or testcode, too.

so in a perfect world the buildsystem is living inside lib1 which is used to build
all examples and tests and another one in the application root that includes the build-rules
from the library and uses these.

== pattern for libraries(with examples and tests) and application

In the library folder there's tundra.lua, library.lua and examples.lua. tundra.lua includes library
and examples as unit-files. because when the library is compiled in the root-folder (examples
from the library itself) or as a subfolder of "extlibs" the buildsystem needs to know the base-path in
libraries.lua; here the option is used to set a variable in the global lua-table. in tundra.lua
is written:

-------------------------------------------------------------------------------
_G.LIBROOT_LIB1 = "."
-------------------------------------------------------------------------------

and in the library.lua you can use this information as the base path:

-------------------------------------------------------------------------------
Sources = {
_G.LIBROOT_LIB1 .. "/file.cpp" ,
Glob { Dir = _G.LIBROOT_LIB1 .. "/", Extensions = {".h"}},
...
-------------------------------------------------------------------------------

now when you want to include the library as part of another application you can set the basepath
in the variable in tundra.lua of the main-application accordingly:

-------------------------------------------------------------------------------
_G.LIBROOT_LIB1 = "extlibs/lib1"
-------------------------------------------------------------------------------

If there is the need to normalize the path this might help you (from John Leidegren):

-------------------------------------------------------------------------------
local path = require "tundra.path"
local LIBROOT_QBGFX = _G.LIBROOT_QBGFX -- or use native.getenv
--I also normalize the path like this
if LIBROOT_QBGFX ~= "." then
LIBROOT_QBGFX = path.normalize(LIBROOT_QBGFX)
end
LIBROOT_QBGFX = LIBROOT_QBGFX .. "/" -- ensure end with trailing slash
-------------------------------------------------------------------------------

== multiple dependencies of libraries

Now if you have a base library (libBase) which is needed by Lib1 AND by the
main application only adding it as a dependency to Lib1 is not enough, you also have to add
it as dependency to the main application!

== own buildrules in the library buildfile

When using some sort of code generator with custom defrules which is provided by the library Lib1 and you
want to be able to use this rule also in the mainapplication you have to add the rule also to the global
lua table (Here we're using some string-concatenation to build different defrules for a shader compiler,
below is the complete block; notice the "function _G.compileVertexShader..."):

-------------------------------------------------------------------------------
local function firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
local function generateShaderCompilerDefRule(build, type, platform, path, profile, addParam)
local addOption = ""
if build == "debug" then
addOption = "--debug"
end
return DefRule {
Name = "ShaderCompiler"..firstToUpper(type)..firstToUpper(platform)..firstToUpper(path)..firstToUpper(build),
Pass = "CodeGeneration",
Command = "$(SHADERCOMPILER) "..addOption.." --type "..type.." --platform "..platform.." -p "..profile.." "..addParam.." -f $(<) -o $(@) -i ".._G.LIBROOT_QBGFX.."/src",
ImplicitInputs = { "$(SHADERCOMPILER)" },
Blueprint = {
Source = { Required = true, Type = "string", Help = "Input filename", },
Output = { Required = true, Type = "string", Help = "Output filename", },
},
Setup = function (env, data)
return {
InputFiles = { data.Source },
OutputFiles = { "$(OBJECTDIR)/shaders/" .. path .. "/" .. data.Output },
}
end,
}
end
generateShaderCompilerDefRule("debug", "fragment", "linux", "glsl", "120", "")
generateShaderCompilerDefRule("debug", "vertex", "linux", "glsl", "120", "")
generateShaderCompilerDefRule("debug", "fragment", "linux", "gles", "100", "")
generateShaderCompilerDefRule("debug", "vertex", "linux", "gles", "100", "")
generateShaderCompilerDefRule("release", "fragment", "linux", "glsl", "120", "")
generateShaderCompilerDefRule("release", "vertex", "linux", "glsl", "120", "")
generateShaderCompilerDefRule("release", "fragment", "linux", "gles", "100", "")
generateShaderCompilerDefRule("release", "vertex", "linux", "gles", "100", "")
function _G.compileVertexShader(inputFile, outputFile)
return {
{Config="*-*-debug"; ShaderCompilerVertexLinuxGlslDebug { Source = inputFile; Output = outputFile;}},
{Config="linux_imx6-*-debug"; ShaderCompilerVertexLinuxGlesDebug { Source = inputFile; Output = outputFile;}},
{Config="*-*-release"; ShaderCompilerVertexLinuxGlslRelease { Source = inputFile; Output = outputFile;}},
{Config="linux_imx6-*-release"; ShaderCompilerVertexLinuxGlesRelease { Source = inputFile; Output = outputFile;}},
}
end
function _G.compileFragmentShader(inputFile, outputFile)
return {
{Config="*-*-debug"; ShaderCompilerFragmentLinuxGlslDebug { Source = inputFile; Output = outputFile;}},
{Config="linux_imx6-*-debug"; ShaderCompilerFragmentLinuxGlesDebug { Source = inputFile; Output = outputFile;}},
{Config="*-*-release"; ShaderCompilerFragmentLinuxGlslRelease { Source = inputFile; Output = outputFile;}},
{Config="linux_imx6-*-release"; ShaderCompilerFragmentLinuxGlesRelease { Source = inputFile; Output = outputFile;}},
}
end
-------------------------------------------------------------------------------

and now these generated defrules can be used(in units.lua from main-app):

-------------------------------------------------------------------------------
Program {
Name = "test",
Sources = {
...
compileVertexShader("vs_cubes.sc", "vs_cubes.bin"),
compileFragmentShader("fs_cubes.sc", "fs_cubes.bin"),
},
Depends = {
...
-------------------------------------------------------------------------------

== how to handle repetetive stuff inside your units.lua

There's often the need to specify an include-directory to a library and also to the main
application, this can be shortened this way:

-------------------------------------------------------------------------------
Env = {
CPPPATH = {
"include",
"examples/common",
....
}
},
Propagate = {
Env = {
CPPPATH = {
"include",
"examples/common",
-------------------------------------------------------------------------------

can be written as:

-------------------------------------------------------------------------------
local repetetive_stuff = {
"include",
"examples/common",
....
}
...
Env = {
CPPPATH = {
repetetive_stuff,
}
},
Propagate = {
Env = {
CPPPATH = {
repetetive_stuff,
}
}
}
-------------------------------------------------------------------------------

18 changes: 18 additions & 0 deletions examples/subproject-organization/extlibs/libA/example.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@

Program {
Name = "example-app",
Sources = {
"exampleThatUsesTheLib.cpp",
--compileVertexShader("vs_cubes.sc", "vs_cubes.bin"),
--compileFragmentShader("fs_cubes.sc", "fs_cubes.bin"),
},
Depends = {
"libA", "defaultConfigurationFromLibA",
},
Env = {
CPPPATH = {
"extlibs/",
},
},
}
Default "example-app"
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

#include "libHeader.h"

#include <stdio.h>

int main(int argc, char **argv) {
printf("Hello World from the library example progam!\n");
libA_process();
return 0;
}
7 changes: 7 additions & 0 deletions examples/subproject-organization/extlibs/libA/libHeader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

#ifndef LIBHEADER_H
#define LIBHEADER_H

void libA_process();

#endif //#ifndef LIBHEADER_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

#include "libHeader.h"

#include <stdio.h>

void libA_process() {
printf("Hello World from the library!\n");
}
38 changes: 38 additions & 0 deletions examples/subproject-organization/extlibs/libA/library.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

-- I want to set a searchpath that is used during compilation of the lib,
-- but also at the compilation of the program using this lib; but I also
-- want to write it only one time :)
local commonEnv = {
CPPPATH = "."
}

ExternalLibrary {
Name = "defaultConfigurationFromLibA",
Propagate = {
-- this should go into the main-app, but is used here as an example
Libs = {Config="win32-*-*"; "User32.lib", "Gdi32.lib" },
},
}

StaticLibrary {
Name = "libA",
Sources = {
-- here you need to add the basepath
_G.LIBROOT_LIBA .. "libHeader.h",
_G.LIBROOT_LIBA .. "libImplementation.cpp",
},
Env = {
commonEnv,
},
Propagate = {
Env = {
commonEnv,
},
},
}

-- if you want to generate own defrules you can define them here and write
-- helper functions to use them by inserting them into the global lua table:
--function _G.useDefRule(arg1, arg2)
-- return { defRule{Source = arg1; Output = arg2;}}
--end
31 changes: 31 additions & 0 deletions examples/subproject-organization/extlibs/libA/tundra.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

_G.LIBROOT_LIBA = "./"

Build {
Units = {
"library.lua",
"example.lua",
},
Configs = {
{
Name = "macosx-gcc",
DefaultOnHost = "macosx",
Tools = { "gcc" },
},
{
Name = "linux_x86-gcc",
DefaultOnHost = "linux",
Tools = { "gcc" },
SupportedHosts = { "linux" },
ReplaceEnv = {
-- Link with the C++ compiler to get the C++ standard library.
LD = "$(CXX)",
},
},
{
Name = "win32-msvc",
DefaultOnHost = "windows",
Tools = { "msvc-vs2013" },
},
},
}
11 changes: 11 additions & 0 deletions examples/subproject-organization/main-app.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

// "extlibs" is in the search path, so I can simply include the library directly
#include "libA/libHeader.h"

#include <stdio.h>

int main(int argc, char **argv) {
printf("Hello World from the main app!\n");
libA_process();
return 0;
}
34 changes: 34 additions & 0 deletions examples/subproject-organization/tundra.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@

_G.LIBROOT_LIBA = "extlibs/libA/"

Build {
Units = {
"extlibs/libA/library.lua",
"units.lua",
},
Configs = {
{
Name = "macosx-gcc",
DefaultOnHost = "macosx",
Tools = { "gcc" },
ReplaceEnv = {
LD = {Config = { "*-gcc-*" }; "$(CXX)"},
},
},
{
Name = "linux_x86-gcc",
DefaultOnHost = "linux",
Tools = { "gcc" },
SupportedHosts = { "linux" },
ReplaceEnv = {
-- Link with the C++ compiler to get the C++ standard library.
LD = "$(CXX)",
},
},
{
Name = "win32-msvc",
DefaultOnHost = "windows",
Tools = { "msvc" },
},
},
}
21 changes: 21 additions & 0 deletions examples/subproject-organization/units.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

Program {
Name = "main-app",
Sources = {
"main-app.cpp",

-- explanation of the next line in extlibs/libA/library.lua
--useDefRule("file1.source", "file1.dest"),
},
Depends = {
-- here we need to include "defaultConfiguration", even if "libA" already has
-- the dependency to the defaultConfiguration!
"libA", "defaultConfigurationFromLibA",
},
Env = {
CPPPATH = {
"extlibs/",
},
},
}
Default "main-app"

0 comments on commit 3fdd5e0

Please sign in to comment.