Overview ======== proj.mk is a Makefile based build tool(inspired by erlang.mk - the best build tool for erlang projects; and by plan9 build mkfiles). Goals ===== - atomatize as much as possible downloading and building of dependencies - handle subdependencies - build a project - try to do these as simple as possible How to use for a program ======================== If you have a small project without dependencies, just run PROJMKDIR/bootstrap.sh from your project directory(where PROJMKDIR is a directory where proj.mk project files are resided - i.e. a directory inside which you cloned proj.mk repo): PROJMKDIR/bootstrap.sh prog-c PROGNAME bootstrap.sh: - create .proj.mk directory - copy proj.mk files excluding git internal files and tests - copy proj.mk file template as PROGNAME.proj.mk - set PROJECT variable in PROGNAME.proj.mk to PROGNAME - create a symlink to proj.mk file with 'Makefile' name. To see all available templates run: PROJMKDIR/bootstrap.sh -h After this execute make command to build a project. If you want to build several binaries, then specify them in TARGET variable: ``` PROJECT := myproj TARGET := myprog1 myprog2 SOURCES := src1.c src2.c src3.c include .proj.mk/c-proj.mk ``` Source files specified in SOURCES will be used for all targets and object file TARGET_NAME.c.o will be add to every target. In the example above this mean that myprog1 have the next objects as prerequisites: myprog1.c.o src1.c.o src2.c.o src3.c.o. If you do not specify TARGET variable, then it value is equal to PROJECT value. If your project have dependencies, then they need to be specified: ``` PROJECT := mybinary SOURCES := mybinary.c another.c DEPS := liba libb2 deps_get_liba := wget http://libsite.org/liba.tgz deps_get_libb := wget http://libsite.org/libb-2.0.txz include .proj.mk/c-proj.mk ``` Here DEPS contains dependencies(by their PROJECT value) and deps_get_* contains how each of them can be obtained(see Schemes of dependency obtaining section). A default target type for a dependency can be overriden with help of deps_ttype_* variables. E.g.: ``` PROJECT := mybinary SOURCES := mybinary.c another.c DEPS := liba libb2 deps_get_liba := wget http://libsite.org/liba.tgz deps_get_libb := wget http://libsite.org/libb-2.0.txz deps_ttype_libb := libso include .proj.mk/c-proj.mk ``` If you want to use a some system library, just add it name which is recognized by pkg-config to DEPS. E.g. for sdl2: ``` DEPS := liba libb2 sdl2 ``` How to use for a library ======================== At first, we must use PROJECT.proj.mk as makefile name(where PROJECT is a value of PROJECT variable), because when we use our library as a dependency in some project with proj.mk, proj.mk detect how to handle building and installing of a dependency based on the presence of PROJECT.proj.mk file. Makefile can be made a symblic link to PROJECT.proj.mk file. To make a library you should specify a lib file name in TARGET: ``` PROJECT := libmy TARGET := libmy.a SOURCES := src1.c src2.c src3.c include .proj.mk/c-proj.mk ``` proj.mk try to detect the correct target type(static library) from the TARGET variable value and set TARGET_TYPE variable to a it. But we can set TARGET_TYPE explicitly: ``` PROJECT := libmy TARGET_TYPE := liba TARGET := libmy.a SOURCES := src1.c src2.c src3.c include .proj.mk/c-proj.mk ``` For a shared library, just change TARGET(and TARGET_TYPE if you use): ``` PROJECT := libmy TARGET := libmy.so SOURCES := src1.c src2.c src3.c include .proj.mk/c-proj.mk ``` If you want to support a building static and shared lib in one project, you can create liba.mk with instructions for static lib(like example above) and libso.mk with instructions for shared lib(like example above) and create the next libmy.proj.mk: ``` TARGET_TYPE ?= liba include $(TARGET_TYPE).mk ``` Thus, by default make will build a static lib and a shared lib with the next command - TARGET_TYPE=libso make . If your liba.mk and libso.mk different only in TARGET value, you can remove liba.mk and libso.mk and make the next libmy.proj.mk: ``` PROJECT := libmy TARGET_TYPE ?= liba SOURCES := src1.c src2.c src3.c include .proj.mk/c-proj.mk ``` In this case TARGET is constructed from PROJECT value and a file extension corresponding to TARGET_TYPE value. To use this lib as dependency for some project we should create a libmy.proj.mk.info file with needed modifications to CFLAGS and LDFLAGS. E.g.: ``` LDFLAGS += -lmy ``` Note that we use += to add needed options to LDFLAGS, bacause proj.mk.info files are used via makefile include directive and if we use = instead of +=, we remove all previously set options. Do not forget about this! How to adapt your library for using in projects with proj.mk ============================================================ To make your library be used from projects with proj.mk you need not to rewrite your makefile with proj.mk. You simply should add YOULIBNAME.proj.mk.info file to a project root directory(for info about a content of this file see above sections). You need to create YOULIBNAME.proj.mk in addition to YOULIBNAME.proj.mk.info only in case when your library have some dependencies you want to be obtained automatically with proj.mk powered project. How to adapt some library for using in your project ================================================== To make some library be used in your project you should add LIBNAME.proj.mk.info file into .proj.mk/db.priv directory(for info about a content of this file see above sections). If you need more control over this library building, installing and handling it dependencies, you can create LIBNAME.proj.mk file in addition to LIBNAME.proj.mk.info. How to perform custom actions before and after build ==================================================== To perform some actions before an all targets building(if TARGET contains many programs) create a build-pre target in your Makefile: ``` build-pre:: echo Starting ... ``` To perform some actions after an all targets building create a build-post target: ``` build-post:: echo Finishing ... ``` How to install your program/library =================================== proj.mk doesn't have yet a default install target, but it try to helps us a little by definition of DESTDIR, PREFIX and D variables. DESTDIR by default is /; PREFIX by default is /usr/local; D by default is $(DESTDIR)/$(PREFIX). Thus if we use D variable when writing a recipe for a install target, then most distros packaging tools and proj.mk dependencies handling will work fine. How it works ============ Let's see what happen(simplified view) when we execute make command: 1. If we have no DEPS, then go to 10 2. If all DEPS are built(i.e. all DEPSDIR/src/DEP.proj.mk.info exist), then go to 10 3. If all DEPS are obtained(i.e. all DEPSDIR/src/.DEP.get exist), then go to 7 4. Create DEPSDIR/* directories, if not exist. 5. Obtain the next dependency from DEPS 6. Create DEPSDIR/src/.DEP.get file 7. Build and install the dependency, if DEPSDIR/src/DEP exist 7.1. if deps_build_DEP defined, run custom command, go to 8 7.2. if PROJDIR/.proj.mk/db.priv/DEP.proj.mk exist, use it, go to 8 7.3. if PROJMKDIR/db.priv/DEP.proj.mk exist, use it, go to 8 7.4. if DEPSDIR/src/DEP/DEP.proj.mk exist, use it, go to 8 7.5. if PROJMKDIR/db/DEP.proj.mk exist, use it, go to 8 7.6. if DEPSDIR/src/DEP/configure exist, run configure, make and make install, go to 8 7.7. run make and make install 8. Create DEPSDIR/src/DEP.proj.mk.info file 8.1. Generate info for DEP itself 8.1.1. if PROJDIR/.proj.mk/db.priv/DEP.proj.mk.info exist, use it, go to 8.2 8.1.2. if PROJMKDIR/db.priv/DEP.proj.mk.info exist, use it, go to 8.2 8.1.3. if DEPSDIR/src/DEP/DEP.proj.mk.info exist, use it, go to 8.2 8.1.4. if DEPSDIR/src/DEP/.proj.mk.info exist, use it, go to 8.2 8.1.5. if PROJMKDIR/db/DEP.proj.mk.info exist, use it, go to 8.2 8.1.6. if pkg-config --exists DEP exit with ecode 0, use it, go to 8.2 8.2. Generate info for DEP dependencies(call 'make projmk_gendepsinfo' with found makefile) 8.2.1. if PROJDIR/.proj.mk/db.priv/DEP.proj.mk exist, use it, go to 9 8.2.2. if PROJMKDIR/db.priv/DEP.proj.mk exist, use it, go to 9 8.2.3. if DEPSDIR/src/DEP/DEP.proj.mk exist, use it, go to 9 8.2.4. if PROJMKDIR/db/DEP.proj.mk exist, use it, go to 9 9. Go to 2 10. Build the project When 'make deps' is executed, then at first DEPSDIR/src/*.proj.mk.info are removed, then steps from 1 to 10 are performed. default target is build: build: build-pre $(TARGET) build-post build-pre and build-post are for custom recipes. Target types ============ TARGET_TYPE variable contains a target type. It can be: - prog - for building a program - liba - for building a static library - libso - for building a shared library If there is no TARGET_TYPE variable, proj.mk try to detect a type of a target from TARGET variable value and set the correct TARGET_TYPE value. Schemes of dependency obtaining =============================== A value of dep_get_* variable has the next format: SCHEME SCHEME_DATA Where SCHEME can be one of: - ln - for a symbolic link creation for the SCHEME_DATA directory - cp - for a recursive copy of the SCHEME_DATA directory - git - for a git-clone of a git repository specified in SCHEME_DATA first word; second optional word of SCHEME_DATA can be commit/branch/tag to git-checkout after git-clone - wget - for downloading via wget a compressed archive from specified SCHEME_DATA uri(support file format is tar.gz, tar.bz2, tar.xz, zip) - custom - for custom commands Build stage =========== Each USE_* variable from Makefile are added to CFLAGS in form -DVARNAME=VARVALUE and can be used in source files. Thus, we can decide functions of which lib to use in our source and support building against various libs with identical purpose. Create a source tarball with all deps ===================================== 'make clean-deps' can be used to execute 'make clean-all' for all deps. After that a source tarball with all deps can be created. At the destination machine 'make deps' can be used to rebuild all deps. Autotests framework =================== After bootstrap.sh finish, there is tests directory in a current directory. This is an autotests framework. Here we can find t001.c file that can be used as a template. Examples ======== See tests directory for examples. Each subdir(t*) can be used as an example. Variables used(interface) ========================= PROJECT - project name(often equal to TARGET); for lib this is used for directory name when lib is used as dependency. DESTDIR - destination directory for install target PREFIX - prefix directory for install target D - $(DESTDIR)/$(PREFIX) DEPS_VARS_RMDUPS - variables names where duplicate words should be removed DEPS_VARS_EXPORT - variables names which should be exported TARGET - a target name OBJS - an objects names for specified target DEPS - project dependencies deps_get_* - specify how to obtain a dependency deps_patch_* - specify patches(separated with spaces) for a dependency deps_build_* - specify how to build and install a dependency deps_ttype_* - specify a dependency target type to build USE_DEP - used dependencies(like USE_libsvsnprintf) USE__* - wanted features(like USE__THREADS) Variables used(internal) ======================== PROJDIR - a project directory(for dependencies - a directory where project that depend on this lib is reside) PROJMKDIR - proj.mk internal directory DEPSDIR - a directory where dependencies will be placed (downloaded,compiled,installed) O - object files extension (o by default) projmk_* - variables and targets names DEPS_ME_IS_DEP - set to 1 if proj.mk detect that project is used as dependency Targets used(interface) ======================= build - default target to build all targets in TARGET variable build-pre - pre build actions(before all targets) build-post - post build actions(after all targets) TARGET - build a TARGET target TARGET-pre - pre build actions(before TARGET target) TARGET-post - post build actions(after TARGET target) TARGET_TYPE - a type of a target(prog, liba) deps - just obtain and build dependencies deps_show - show dependencies recursively clean - clean *~ and *.o clean-deps - do make clean-all for all deps clean-tests - do $(MAKE) -C tests clean clean-all - do clean-tests, clean, clean-deps-all tests - do $(MAKE) -C tests Targets used(internal) ====================== DEPSDIR/src/DEP.proj.mk.info - dependency build flag for DEP dependency (remove to rebuild a dependency) DEPSDIR/src/.DEP.get - dependency obtain flag for DEP dependency (remove to reobtain a dependency) deps_ - obtain and build dependencies deps_genfullinfo - Conventions =========== Variables that some dependencies want: USE__THREADS - NO/PTHREAD - what thread implementation to use