From 46d272892e2bb070e694e36cc9a9e58988032094 Mon Sep 17 00:00:00 2001 From: Björn Persson Date: Thu, 1 Aug 2013 18:25:26 +0200 Subject: Added support for separate build directories and for usage projects in subdirectories. --- comfignat.gpr.gp | 9 ++- comfignat.mk | 205 ++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 150 insertions(+), 64 deletions(-) diff --git a/comfignat.gpr.gp b/comfignat.gpr.gp index d5bcd78..3b0c950 100644 --- a/comfignat.gpr.gp +++ b/comfignat.gpr.gp @@ -204,11 +204,18 @@ abstract project Comfignat is -- generated files are placed. -- + -- Various generated files are kept in Builddir. + #if Builddir'Defined then + Builddir := $Builddir; + #else + Builddir := "."; + #end if; + -- Intermediate files produced during the build shall be kept in Objdir. #if Objdir'Defined then Objdir := $Objdir; #else - Objdir := "build"; + Objdir := Builddir & "/obj"; #end if; #if Directories_Project'Defined then diff --git a/comfignat.mk b/comfignat.mk index e90c9fb..5c5e62a 100644 --- a/comfignat.mk +++ b/comfignat.mk @@ -106,9 +106,10 @@ lockdir = ${runtimedir}/lock # These are the directories where different kinds of files will be located on # the target system. -builddir = ${CURDIR}/build +builddir = ${CURDIR} objdir = ${builddir}/obj stagedir = ${builddir}/stage +# builddir is the build directory, which may be separate from the source tree. # Intermediate files produced during the build are kept in objdir. Files to be # installed are written to stagedir, and then copied to their destination in # the installation step. @@ -125,15 +126,52 @@ install_cp_flags = ${if ${DESTDIR},--preserve=timestamps} # -# Containing makefiles should assign or append to these variables as needed: +# Containing makefiles may use these variables in their rules, but nothing +# should modify them: # -ifneq (${origin preprocessed_files},file) - preprocessed_files := ${basename ${wildcard *.gp}} -endif -# preprocessed_files is a list of files to be produced in the preprocessing -# step at the beginning of the build. Containing makefiles may override it or -# append additional filenames to it. +srcdir := ${abspath ${dir ${lastword ${MAKEFILE_LIST}}}} +# srcdir is the root of the source tree, computed as the directory part of the +# last pathname in MAKEFILE_LIST – which is this file since there is no include +# directive above this point. + +stage_bindir = ${stagedir}${bindir} +stage_libexecdir = ${stagedir}${libexecdir} +stage_datadir = ${stagedir}${datadir} +stage_sysconfdir = ${stagedir}${sysconfdir} +stage_statedir = ${stagedir}${statedir} +stage_cachedir = ${stagedir}${cachedir} +stage_logdir = ${stagedir}${logdir} +stage_includedir = ${stagedir}${includedir} +stage_libdir = ${stagedir}${libdir} +stage_gprdir = ${stagedir}${gprdir} +stage_localedir = ${stagedir}${localedir} +stage_mandir = ${stagedir}${mandir} +stage_infodir = ${stagedir}${infodir} +stage_miscdocdir = ${stagedir}${miscdocdir} +# These are the directories where different kinds of files to be installed are +# written during the build. + +preprocess_file = "${GNATPREP}" ${firstword ${filter %.gp,$^}} $@ \ + ${options_preprocessing} ${Gnatprep_arguments} \ + ${if ${filter ${notdir $@},${notdir ${usage_GPRs}}}, \ + ${usage_directories}, \ + '-DSrcdir="${srcdir}"'} +# preprocess_file is a command for use in recipes. It runs the first .gp file +# among the rule's prerequisites through Gnatprep to produce the target. If the +# target is a usage project, then the usage-relevant directory variables are +# conveyed to it as Gnatprep symbols. Otherwise srcdir is conveyed. + +build_GPR = "${GNAT_BUILDER}" -P ${firstword ${filter %.gpr,$^}} \ + -aP${srcdir} -aP${builddir} -p \ + ${options_building} ${builder_arguments} ${GNATFLAGS} +# build_GPR is a command for use in recipes. It performs a build controlled by +# the first project file among the rule's prerequisites. + + +# +# Containing makefiles should assign or append to these variables as needed: +# ifneq (${origin build_GPRs},file) build_GPRs = @@ -148,6 +186,18 @@ endif # that other projects should import to link to the libraries. These project # files will be installed to the target system. +ifneq (${origin preprocessed_files},file) + preprocessed_files = \ + ${filter-out ${notdir ${usage_GPRs}}, \ + ${basename ${notdir ${wildcard ${srcdir}/*.gp}}}} +endif +# preprocessed_files is a list of files to be produced in the preprocessing +# step at the beginning of the build. Containing makefiles may override it or +# append additional filenames to it. +# The files are assumed to be needed during the build. The default list is all +# the .gp files in srcdir except for usage projects, minus the .gp suffix. This +# includes comfignat.gpr. + ifneq (${origin options},file) options = endif @@ -172,6 +222,9 @@ endif # default values for optional arguments should be set in the options variables # instead. +VPATH += ${srcdir} ${builddir} +# VPATH is a list of directories that Make should search for prerequisites. + configuration_variables += \ GNATPREP GNAT_BUILDER \ GNAT_BUILDER_FLAGS ADAFLAGS CPPFLAGS CFLAGS CXXFLAGS FFLAGS GNATBINDFLAGS \ @@ -181,7 +234,7 @@ configuration_variables += \ prefix exec_prefix datarootdir localstatedir \ bindir libexecdir datadir sysconfdir statedir cachedir logdir includedir \ libdir gprdir localedir mandir infodir miscdocdir runtimedir lockdir \ - builddir objdir stagedir \ + objdir stagedir \ install_cp_flags \ ${options} # configuration_variables is a list of variables that can be saved in the @@ -190,50 +243,41 @@ configuration_variables += \ # -# Containing makefiles may use these variables in their rules: +# Read the configuration file if there is one: # -stage_bindir = ${stagedir}${bindir} -stage_libexecdir = ${stagedir}${libexecdir} -stage_datadir = ${stagedir}${datadir} -stage_sysconfdir = ${stagedir}${sysconfdir} -stage_statedir = ${stagedir}${statedir} -stage_cachedir = ${stagedir}${cachedir} -stage_logdir = ${stagedir}${logdir} -stage_includedir = ${stagedir}${includedir} -stage_libdir = ${stagedir}${libdir} -stage_gprdir = ${stagedir}${gprdir} -stage_localedir = ${stagedir}${localedir} -stage_mandir = ${stagedir}${mandir} -stage_infodir = ${stagedir}${infodir} -stage_miscdocdir = ${stagedir}${miscdocdir} -# These are the directories where different kinds of files to be installed are -# written during the build. +configuration = ${builddir}/comfignat_configuration.mk -preprocess_file = \ - ${if ${filter-out 1,${words $^}}, \ - ${error preprocess_file takes 1 prerequisite but $@ has ${words $^}}, \ - "${GNATPREP}" $< $@ ${options_preprocessing} ${Gnatprep_arguments} \ - ${if ${filter $@,${usage_GPRs}},${usage_directories}}} -# preprocess_file is a command for use in recipes. It runs the rule's single -# prerequisite through Gnatprep to produce the target. - -build_GPR = "${GNAT_BUILDER}" -P ${firstword ${filter %.gpr,$^}} -p \ - ${options_building} ${builder_arguments} ${GNATFLAGS} -# build_GPR is a command for use in recipes. It performs a build controlled by -# the first project file among the rule's prerequisites. +-include ${configuration} # -# Read the configuration file if there is one: +# Ensure that builddir, objdir and stagedir are absolute pathnames: # --include comfignat_configuration.mk +ifeq (${origin builddir},command line) + override builddir := ${abspath ${builddir}} +endif +ifeq (${origin objdir},command line) + override objdir := ${abspath ${objdir}} + objdir_is_configured = true +endif +ifeq (${origin stagedir},command line) + override stagedir := ${abspath ${stagedir}} + stagedir_is_configured = true +endif +# These pathnames need to be absolute in project files, because a pathname +# relative to a project file can be wrong when a separate build directory is +# used and project files are both in srcdir and in builddir. objdir and +# stagedir also need to be absolute in the configuration file because the +# working directory might change between Make invocations. +# Once modified the variables are no longer of command line origin, so they are +# marked as configured so that "make configure" will save them. # -# Compute symbol definitions for Gnatprep, external variable assignments for -# build projects, and some other data that the rules need: +# Compute symbol definitions for Gnatprep and external variable assignments for +# build projects: # nil = @@ -311,8 +355,9 @@ usage_pathname = ${call maybe_relative_to,${1},${gprdir}} # inclusion in a usage project, which means that it is made relative to gprdir # if a relocatable package is desired. -# Convey objdir and stagedir to comfignat.gpr. -all_directories = '-DObjdir="${objdir}"' '-DStagedir="${stagedir}"' +# Convey builddir, objdir and stagedir to comfignat.gpr. +all_directories = '-DBuilddir="${builddir}"' '-DObjdir="${objdir}"' \ + '-DStagedir="${stagedir}"' # Convey the builder-irrelevant directory variables, making them available to # build projects for inclusion in binaries. Make most of the pathnames relative @@ -391,13 +436,26 @@ options_preprocessing = ${addprefix -D,${option_values}} # Convey boolean options to build projects. options_building = ${addprefix -X,${option_values}} + +# +# Some other data that the rules below need: +# + +delegation_command := @$${MAKE} --file=${abspath ${firstword ${MAKEFILE_LIST}}}\ + --include-dir=${srcdir} --no-print-directory +# delegation_command is the Make command line that delegating makefiles in +# separate build directories use to delegate commands to the main makefile. The +# first pathname in MAKEFILE_LIST is the main makefile. + build_targets = ${addsuffix .phony_target,${build_GPRs}} # A phony target is defined for each build project, and the job of determining # whether the project needs rebuilding is delegated to the builder. -stage_any_GPRs = ${if ${usage_GPRs},stage_GPRs} -# The recipe for the target stage_GPRs breaks if usage_GPRs is empty, so it's -# included as a prerequisite of build only if there are some usage projects. +staged_usage_GPRs = ${addprefix ${stage_gprdir}/,${usage_GPRs}} +preprocessed_files_in_builddir = ${addprefix ${builddir}/,${preprocessed_files}} +# When usage projects are preprocessed they are written to stage_gprdir. Other +# preprocessed files are assumed to be needed during the build and are written +# to builddir. # @@ -406,9 +464,27 @@ stage_any_GPRs = ${if ${usage_GPRs},stage_GPRs} .SECONDEXPANSION: -default: build - -configure:: +Comfignat_default_goal: build + +${builddir} ${stage_gprdir}: + mkdir -p $@ + +${builddir}/Makefile: | ${builddir} + @echo 'Writing $@.' + @( echo 'Comfignat_default_goal: force ; ${delegation_command}'; \ + echo '%: force ; ${delegation_command} $$@'; \ + echo 'force: ;'; \ + echo 'Makefile: ;' \ + ) > $@ +# This rule generates a delegating makefile in a separate build directory. The +# generated makefile delegates all commands to the main makefile. The default +# rule invokes the main makefile without a specified goal, triggering the main +# makefile's default goal. A match-anything rule forwards any specified goals +# to the main makefile. An empty recipe for "Makefile" prevents Make from using +# the match-anything rule to update the makefile. + +configure:: ${builddir}/Makefile + @echo "Writing ${configuration}." @( ${foreach variable,${configuration_variables}, \ ${if ${or ${findstring command line, \ ${origin ${variable}}}, \ @@ -417,7 +493,8 @@ configure:: echo 'override ${variable} = ${value ${variable}}'; \ echo 'endif'; \ echo '${variable}_is_configured = true';}} \ - ) > comfignat_configuration.mk + true \ + ) > "${configuration}" # Out of the variables listed in configuration_variables, all that were # overridden on the command line, and all that were previously configured, are # written to the configuration file. Configured values override defaults @@ -428,25 +505,27 @@ configure:: # therefore possible to delete a variable V from the configuration by running # "make configure V_is_configured=false". -comfignat.gpr: comfignat.gpr.gp +${builddir}/comfignat.gpr: comfignat.gpr.gp | ${builddir} "${GNATPREP}" $< $@ -DInvoked_By_Makefile ${all_directories} -%.gpr: %.gpr.gp +${builddir}/%: %.gp | ${builddir} ${preprocess_file} -preprocess: $${preprocessed_files} +${stage_gprdir}/%: %.gp | ${stage_gprdir} + ${preprocess_file} + +${stage_gprdir}/%: % | ${stage_gprdir} + cp -p $< $@ + +preprocess: $${preprocessed_files_in_builddir} %.gpr.phony_target: %.gpr preprocess ${build_GPR} # Instead of tracking dependencies between project files, this rule simply -# requires that all preprocessing is done before any project is built. - -stage_GPRs: $${usage_GPRs} - mkdir -p "${stage_gprdir}" - cp -p ${usage_GPRs} "${stage_gprdir}" -.PHONY: stage_GPRs +# requires that all preprocessing of files that are needed during the build is +# done before any project is built. -build: $${build_targets} $${stage_any_GPRs} +build: $${build_targets} $${staged_usage_GPRs} ${stagedir}: @${MAKE} build --no-print-directory @@ -460,9 +539,9 @@ install: ${stagedir} .PHONY: install clean:: - rm -Rf ${builddir} ${preprocessed_files} + rm -Rf "${objdir}" "${stagedir}" ${preprocessed_files_in_builddir} unconfigure:: - rm -f comfignat_configuration.mk + rm -f "${configuration}" distclean: clean unconfigure -- cgit v1.2.3