Makefile CCCP
From MohidWiki
This section describes a Cross-Compiler, Cross-Platform (CCCP) makefile development methodology using the make tool from GNU, also known as gmake. The syntax to use would be:
make platform.action
(ex: make Win, make Unix.clean, etc...).
Description
A CCCP makefile project a bunch of library, modules and program folders within a single root folder.
Tree description
Regular folders
Every folder must contain the following files:
- Files.mk
- encapsulates a list of all the folder's source-files and meta-files. Several variables are defined:
- INCS
- LIBS
- SRCDIR
- contains the path to the source files
- FILES
- contains the list of source files (using the $(S) suffix)
- METAFILES
- contains the list of files required by the Makefile to run in this project (using the .smk suffix)
- TARGET
- is the target name that the local makefile is supposed to build.
- MODULES
- contains the list of modules (special root folder only).
- Makefile
- contains includes to all the actions that can be perfomed on the folder.
- Dependencies.mk
- encapsulates the dependencies of the files within the lists defined in Files.mk.
Special folders and special files
There are two special folders, mandatory, and each containing special files, beyond the mandatory regular files listed above:
- the root folder
- Actions.mk
- is similar to Makefile, but defines PHONY targets that executes the different actions defined in the Makefiles special folder.
- Nix.mk
- contains all the necessary configuration global variables specific to the CCCP solution. Configured by the Solution administrator.
- Editme.mk
- Each user must edit this configuration file before building the solution.
- the Makefiles folder (NOTE: it is extensible, one file per action or rule)
- All.mk
- contains the makefile rules to compile and build programs.
- Alllib.mk
- contains the makefile rules to compile and build libraries.
- Clean.mk
- contains the makefile rules to erase every .obj, .mod, .lib and .exe file that was created by the CCCP solution.
- Install.mk
- contains the makefile rule to install the programs.
The makefile's global variables
The idea is to use global variables to pass arguments to the different modules makefiles. Thus, each specific platform makefile in the root folder defines these global variables. Then, it calls the modules makefiles who will use the global variables in their syntax. If a systematic approach of using global variables is implemented, then it is fairly easy to have a cross-platform makefile project implemented; and easily extended.
The template code
Special root folder's Makefile
SHELL = /bin/sh export MAKE = make .PHONY: default default: @echo Please choose your platform from: @echo Type "make (win nix).(' ' clean install sos)". #make all (add other platforms "Nix Nix Nix_double Win" ...) PLAT := Nix .PHONY : $(PLAT) $(PLAT): $(MAKE) -f $@.mk all #make clean PLATCLEAN := $(addsuffix .clean, $(PLAT)) .PHONY : $(PLATCLEAN) $(PLATCLEAN) : $(MAKE) -f $(@:.clean=).mk clean #make install PLATINST := $(addsuffix .install, $(PLAT)) .PHONY : $(PLATINST) $(PLATINST) : $(MAKE) -f $(@:.install=).mk install
Special root folder's Actions.mk
#make all MODALL = $(addsuffix .all, $(MODULES)) .PHONY: all $(MODALL) all: $(MODALL) $(MODALL): -$(MAKE) -C $(@:.all=) all #make clean MODCLEAN = $(addsuffix .clean, $(MODULES)) .PHONY: clean $(MODCLEAN) clean: $(MODCLEAN) $(MODCLEAN): -$(MAKE) -C $(@:.clean=) clean #make install MODINSTALL = $(addsuffix .install, $(MODULES)) .PHONY: install $(MODINSTALL) install: $(MODINSTALL) $(MODINSTALL) : -$(MAKE) -C $(@:.install=) install
Special root folder's Nix.mk
SHELL = /bin/sh ###### NIX Exported variables ######### export CP = sudo cp export DEL = rm export O = o export F = F90 export MOD = mod export CC= ifort export CCFLAGS = -c -fpp -warn all -nologo -convert big_endian -D_USE_NIX# Debug: -g Profiling: -p export LFLAGS = -fpp -nologo -warn all -i-static -convert big_endian -D_USE_NIX# Profiling: -p export LLFLAGS = export AR = ar rc export SRCBASE1 = ../../../Shared/MOHID.Base.1 export SRCBASE2 = ../../../Shared/MOHID.Base.2 export SRCWATER = ../../../Modulus.Software/MOHID.Water export BASE1INC = ../Mohid_Base_1 export BASE1 = Mohid_Base_1.lib export BASE2INC = ../Mohid_Base_2 export BASE2 = Mohid_Base_2.lib export WATER = MohidWater export LHDF5FORTRAN = libhdf5_fortran.a export LHDF5 = libhdf5.a export LHDF5HL = libhdf5_hl.a export ZLIB = libz.a export BASELIBS = \ $(BASE1INC)/$(BASE1) \ $(BASE2INC)/$(BASE2) \ $(HDF5)/$(LHDF5FORTRAN) \ $(HDF5)/$(LHDF5) \ $(HDF5)/$(LHDF5HL) \ $(ZLIBINC)/$(ZLIB) export LNETCDF = netcdf.a export NETCDFLIBS := \ $(BASELIBS) \ $(NETCDFINC)/$(LNETCDF) #### End of exported variables #### include Editme.mk include Files.mk include Actions.mk include Dependencies.mk
Regular folder Makefile
SHELL = /bin/sh include Files.mk include ../Makefiles/Install.mk include ../Makefiles/Clean.mk include ../Makefiles/Alllib.mk include Dependencies.mk
Regular folder typical Files.mk
INCS = -I$(HDF5) LIBS = SRCDIR = $(SRCBASE1) FILES = \ ModuleGlobalData.$(S) \ ModuleDrainageNetwork.$(S) \ ModuleProfile.$(S) METAFILES = \ Files.smk \ Dependencies.smk TARGET = $(BASE1)
Regular folder typical Dependencies.mk
A sample project for Mohid2D (DEPRECATED)
Here we apply the methodology described above.
Makefile
SHELL = /bin/sh export MAKE = make PLATCLEAN = win.clean nix.clean PLAT = $(PLATCLEAN:.clean=) .PHONY: default $(PLATCLEAN) $(PLAT) default: @echo Please choose your platform from: @echo $(PLAT). @echo Type "make win(.clean)" or "make nix(.clean)". $(PLAT): $(MAKE) -f $@.mk all $(PLATCLEAN) : $(MAKE) -f $(@:.clean=).mk clean
win.mk
SHELL = /bin/sh ###### WIN Exported variables ######### export DEL = del /Q export O = obj export F = f90 export MOD = mod export CC= ifort export CCFLAGS = -c -fpp -nologo # Debug: -g Profiling: -p export LFLAGS = -fpp -nologo # Profiling: -p export AR = ar rc export HDF5 = D:/Projectos/Mohid_v4/IntelLibs export LIBS = \ ../Library/Library.lib \ ../Modulos/Modulos.lib \ ../Boxdif_hidrodin/Boxdif_hidrodin.lib \ ../Mohid_Base/Mohid_Base.lib \ $(HDF5)/hdf5.lib \ $(HDF5)/hdf5_hl.lib \ $(HDF5)/hdf5c.lib \ $(HDF5)/hdf5f90.lib \ $(HDF5)/szlib.lib \ $(HDF5)/zlib.lib #### End of exported variables #### include aux.mk
nix.mk
SHELL = /bin/sh ###### NIX Exported variables ######### export DEL = rm export O = o export F = f90 export MOD = mod export CC= ifort export CCFLAGS = -c -fpp -nologo # Debug: -g Profiling: -p export LFLAGS = -fpp -nologo # Profiling: -p export AR = ar rc export HDF5 = /opt/hdf5/hdf5/lib export LIBS = \ ../Boxdif_hidrodin/Boxdif_hidrodin.lib \ ../Mohid_Base/Mohid_Base.lib \ ../Modulos/Modulos.lib \ ../Library/Library.lib \ $(HDF5)/libhdf5_fortran.a \ $(HDF5)/libhdf5.a \ $(HDF5)/libhdf5_hl.a #### End of exported variables #### include aux.mk
aux.mk
MODCLEAN = Modulos.clean Boxdif_hidrodin.clean Library.clean Mohid_Base.clean Mohid2D.clean MODULES = $(MODCLEAN:.clean=.all) .PHONY: all clean $(MODULES) $(MODCLEAN) all: $(MODULES) clean: $(MODCLEAN) $(MODULES): $(MAKE) -C $(@:.all=) all $(MODCLEAN): $(MAKE) -C $(@:.clean=) clean #Modules dependencies Mohid2D.all: Mohid_Base Library.all Mohid_Base.all: Boxdif_hidrodin.all Library.all: Modulos.all
ModuleA/Vars.mk
SHELL = /bin/sh INCS = -I../ -I$(HDF5) SRCS = \ ModuleGlobalData.$(F) \ ModuleHDF5.$(F) \ ModuleTime.$(F) \ Module_EnterData.$(F) \ ModuleOilSpill.$(F) \ ModuleAppPART3D.$(F) \ ModuleEuler.$(F) \ ModuleOxygenSaturation.$(F) TARGET = Modulos.lib
ModuleA/Makefile
include Vars.mk OBJS = $(SRCS:.$(F)=.$(O)) .PHONY: all clean all: $(TARGET) $(TARGET) : $(OBJS) @$(AR) $@ $^ @echo Finished building $@. clean: @-$(DEL) *.$(O) *.$(MOD) $(TARGET) @echo Erased $(TARGET) files. %.$(O) : %.$(F) @$(CC) $(CCFLAGS) $(INCS) $< @echo $* .............. [OK] include Dependencies.mk
ModuleA/Dependencies.mk
#Dependencies ModuleHDF5.$(O) : ModuleGlobalData.$(O) Module_EnterData.$(O) : ModuleTime.$(O) ModuleOilSpill.$(O) : Module_EnterData.$(O) ModuleAppPART3D.$(O) : ModuleOilSpill.$(O) ModuleEuler.$(O) : ../param.cmb