Concerto is a simple single-pass, non-recursive, full dependency-managed Makefile system.
Concerto looks for sub-makefiles called concerto.mak in the directories (and their corresponding subdirectories) specified by the DIRECTORIES variable. It will "include" each module's concerto.mak file into the overall build and resolve all build related macros associated with that module. In this way, it is "single pass" in that all concerto.mak makefiles are read once. The Concerto Build System makefiles like the prelude.mak and finale.mak (and submakefiles therein) are read once per module. These are used to define the make-target macros needed to establish the full depedency tree of the entire build system.
definitions.mak- useful macros for finding source filesrules.mak- internal top level file. Include this in your Makefile.os.mak- determines host osmachine.mak- determines host cputarget.mak- determines target variables and build system include paths, variables. This can be replaced (see above).scm.mak- tries to extract SCM version information (SVN/GIT)prelude.makandfinale.mak- generates non-recursive build system macros and variables per module.compilers/*- Compiler specific filesos/*- OS specific installing/removing rulestools/*- tools specific rules.components/*- contains rules to build with components that do not work well with standard package management tools like pkg-configshell.mak- Contains shell macros per OS.combo.makandcombo_filters.mak- contains rules to simulatenously build on multiple compilers.packages.mak- contains package management rules per OS.
- Download or copy the concerto folder to somewhere on your build system from
git clone https://github.com/emrainey/Concerto - Create a Makefile at the top of you project consisting of the following:
Top Level Makefile per project
# Path to concerto install or use environment variable
CONCERTO_ROOT ?= ../concerto
# [OPTIONAL] if DIRECTORIES is not specified concerto assumes "source"
DIRECTORIES := src docs
# [OPTIONAL] BUILD_TARGET is used to reflect specific needs of your build system.
# if not specified concerto's default target.mak is used instead
BUILD_TARGET := $(abspath .)/target.mak
# [REQUIRED] This calls concerto
include $(CONCERTO_ROOT)/rules.mak
How to auto-download if Concerto is not present
# Path to concerto install or use environment variable
CONCERTO_ROOT ?= ../concerto
# [OPTIONAL] check to see if the path really exists to CONCERTO_ROOT, if it does not, execute a shell command to pull it down with git
$(if $(realpath $(CONCERTO_ROOT)),,$(call $($(shell git clone http://github.com/emrainey/Concerto $(CONCERTO_ROOT)))))
...
# This calls concerto
include $(CONCERTO_ROOT)/rules.mak
concerto.mak files can contain the following (although it is normally shorter):
_MODULE=<optional module name>
include $(PRELUDE)
TARGET=<name of the object created>
TARGETTYPE=<exe|library|dsmo|prebuilt|jar>
CSOURCES=<list of C files>
CPPSOURCES=<list of C++ files>
ASSEMBLY=<list of .S Files>
KCSOURCES=<list of KernelC .k files>
IDIRS+=<include directories>
DEFS+=<defines>
STATIC_LIBS=<static libraries within the build system>
SHARED_LIBS=<shared libraries within the build system>
SYS_STATIC_LIBS=<static libraries outside the build system>
SYS_SHARED_LIBS=<shared libraries outside the build system>
LINKER_FILES=<list of linker files within the build system>
PREBUILT=<It specifies a single resource to be copied into the target output, only used with the prebuilt TARGETTYPE>
include $(FINALE)
A typical concerto.mak is shorter:
include $(PRELUDE)
TARGET=mytest
TARGETTYPE=exe
SYS_STATIC_LIBS+=some_system_lib
CSOURCES=main.c
include $(FINALE)
The following variables and macros are available for use in a concerto.mak file.
_MODULE- the name of the module (if not defined, the containing folder name will be used).TARGET- the name of the component to build. Prefixes and postfixes will be added by the build system, do not add them yourself.TARGETTYPE- possible values are:
- exe - binary executable
- library - static library
- dsmo - dynamic shared library
- prebuilt - a prebuilt binary
- jar - a Java jar file
- doxygen - A doxygen build
- deb - A debian package (control file is required)
SYS_SHARED_LIBS- dynamic libraries for which no dependencies are generated (which implies that they are outside the build system).SYS_STATIC_LIBS- static libraries for which no dependencies are generated (which implies that they are outside the build system).SHARED_LIBS- dynamic libraries for which dependencies are generated (which implies that they are inside the build system).STATIC_LIBS- static libraries for which dependencies are generated (which implies that they are inside the build system).ASSEMBLY- S files which must be in the same folder.CSOURCES- C files which must be in the same folder.CPPSOURCES- C++ files which must be in the same folder.JSOURCES- Java files for Jar targetsIDIRS- include directoriesLDIRS- library link pathsDEFS- #defines to pass to the compiler
# list of files with extension .ext in "dir" and any sub-directory of "dir"
$(call all-type-files-in,<ext>,<dir>)
# list of files with extension .ext that exist inside this module (including any sub-directories)
$(call all-type-files,<ext>)
# list of c files c that exist inside this module (including any sub-directories)
$(call all-c-files)
# list of c files c that exist in dir (including any sub-directories). dir is relative to the module directory
$(call all-c-files-in,<dir>)
See definitions.mak and shell.mak for other supported file extensions.
The preceding variables can be set in the command shell and make will import them.
NO_OPTIMIZE=1- disables optimization in the compiler. The target build will be built follow normal debugging flags on this platform.CHECK_MISRA=1- it enables misra compliance checking however it is compiler dependantKEEP_ASM=1- it keeps generated assembly listings however it is compiler dependantKEEP_VCC=1- keep generated VCOP-C code however this is for ARP32/VCOP compiler onlyBUILD_DEBUG=1- turns on explicit build output from each commandTARGET_PLATFORM- indicates the platform to build for (assumes 'PC' if not set).TARGET_OS= LINUX or Windows_NT or DARWIN or QNXTARGET_CPU= ARM or X86 or X86_64 or c64t or c67xTARGET_BUILD= debug or release or production - used to generate debuggable components, optimized components or finale builds.HOST_OS= LINUX or Windows_NTHOST_CPU= X86 or X86_64HOST_PLATFORM= PC (ususally)
Host Environments:
- LINUX
- DARWIN
- WINDOWS (NT or later)
- CYGWIN
Target Environments:
- LINUX
- DARWIN
- WINDOWS (NT or later)
- CYGWIN
- QNX
Target CPUs:
- ARM
- X86
- X86_64
- TI DSPs
When building on Windows, you need to install MinGW to get the GNU Make for Windows. Add the path to MinGW's bin/ folder to your PATH variable. You may want to rename or copy it from mingw32-make.exe to make.exe.
Concerto provides the following useful rules:
make scrub This will delete the build output directory
make targets Lists all targets defined by concerto.mak files
make <target> This will build the specified target and any of its dependencies
make <target>_clean Cleans out the specified target
make clean Cleans out all build artifacts for all targets
make vars Outputs the module variables as concerto thinks they are. Useful for debugging.
The typical folder layout (the default configuration) is:
project_folder/
- Makefile
- include/
- source/any depth of folders/concerto.mak
- out/$(TARGET_PLATFORM)/$(TARGET_CPU)/$(TARGET_OS)/$(TARGET_BUILD)/components
For multiproject builds the layout is just all project_folder folders as peers within a parent folder which will have the out folder as a child. The Makefile for a multiproject build simply notes the subdirs of the build.
DIRECTORIES := someproject/source someproject/docs
DIRECTORIES += otherproject/source otherproject/docs
Concerto has to be careful to make sure no _MODULES are named the same in these two projects, so it alters the _MODULE name to guarentee uniqueness (otherwise you would have two components share the same output folder for intermediate objects and you may be compiler/linker collisions and very odd behavior).