mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-15 17:33:38 +00:00
Before this diff,
- the .d filed generated by "mmc --generate-dependencies mer_std.m", and
- the .d files generated by compiling all the modules in the library
had *two*-way differences: the first set of .d files contained dependencies
that the second did not, and *vice versa*. The latter differences were bugs.
Now, as far as I can tell from the deluge of data,
"mmc --generate-dependencies" generates a superset of the dependencies
generated by code generating compiler invocations, which is a safe
overapproximation of the actual dependencies.
compiler/generate_mmakefile_fragments.m:
Flatten the d_file_deps structure by effectively inlining the std_deps
structure inside it, and putting the resulting fields into a meaningful
order. Document the resulting structure as well as I can.
Use notag types to record the intended semantics of some fields
into their values, with the intention of making them harder to misuse.
They were misused before this diff; in particular, a missing module
name in one of these fields would reliably lead to the failure
of the hard_coded/foreign_import_module test case in hlc grades,
though only with a sequential invocation of mmake. (The bug was
that after "mmc --generate-dependencies foreign_import_module.m",
foreign_import_module.d was missing the dependency of
foreign_import_module.o on foreign_import_module_helper_1.mh,
and therefore the compilation foreign_import_module.c got a gcc abort
complaining about this .mh file being missing. The reason for
the bug being intermittent was that the mmc invocation that created
foreign_import_module.c would add the missing dependency, so *later*
mmake invocations, though not existing ones, would know
to build that .mh file.)
Generate rules for object files depending on .mh files that
account for both foreign_import_module declarations, and for
foreign type definitions. Add an XXX about the absence of the
information we need to properly handle the latter in the presence
of intermodule optimization.
Generate just one rule for object files depending on .mh files,
instead of generating two (one for the dependencies that exist
without intermodule optimization, and for one those that exist only
with intermodule optimization.)
Flatten the intermod_deps structure as well. It used to have two
components that encoded the outcomes of two *almost* identical tests,
but a change to d_file_deps.m below makes them actually identical,
so they do not need to be recorded twice.
Inline the old (and misnamed) gather_foreign_import_deps predicate
at its only call site, for greater clarity.
Simplify the code constructing some actions.
Use more specifically descriptive predicate and variable names.
compiler/d_file_deps.m:
Stop requiring the caller of construct_d_file_deps_gendep to pass
an aug_compilation_unit; get it to pass instead two of its components,
the only ones that are meaningful and also the only ones we actually need:
the parse_tree of the module in question and its baggage.
Eliminate some unnecessary differences between compute_d_file_deps_gendep
and compute_d_file_deps_hlds by replacing some existing tests for just
--intermod-opt with tests for *either* --intermod-opt *or* --use-opt-files,
which is the test used elsewhere for the same purpose in the rest of this
module. The two tests are equivalent for now, because handle_options.m
force-sets --no-use-opt-files. And even when we undo that force-set,
the new test will actually be what we want.
Completely redo the code that computes the dependencies that
generate_mmakefile_fragments.m converts into the dependencies
of object files on .mh files.
Give some predicates more meaningful names.
compiler/mmakefiles.m:
Add a mechanism to allow the simplification of some codes
creating actions.
compiler/module_deps_graph.m:
Give a type a more descriptive name.
Document a predicate.
Add an XXX.
compiler/make.program_target.m:
compiler/write_deps_file.m:
Conform to the changes above.
compiler/intermod.m:
Fix comment rot.
compiler/parse_tree_out_item.m:
Generate more readable output for foreign_enum pragmas.
library/digraph.m:
Put the predicates/functions of this file into meaningful groups.
We have several operations that have two names, one old and short,
and one newer, longer and more descriptive. Implement the short named
versions in terms of the longer named versions, not vice versa.
Give some internal predicates more meaningful names.
There are no algorithmic changes in this module.
browser/Mmakefile:
Update a comment.
scripts/mmake.in:
Allow $MMAKE_DEBUG to specify what debug flags to invoke gmake with.
403 lines
11 KiB
Bash
403 lines
11 KiB
Bash
#! /bin/sh
|
|
#---------------------------------------------------------------------------#
|
|
# vim: ts=4 sw=4 et ft=sh
|
|
#---------------------------------------------------------------------------#
|
|
# @configure_input@
|
|
#---------------------------------------------------------------------------#
|
|
# Copyright (C) 1995-1999,2001-2005 The University of Melbourne.
|
|
# Copyright (C) 2013, 2016, 2019-2020, 2025 The Mercury team.
|
|
# This file may only be copied under the terms of the GNU General
|
|
# Public License - see the file COPYING in the Mercury distribution.
|
|
#---------------------------------------------------------------------------#
|
|
#
|
|
# mmake - Mercury Make.
|
|
#
|
|
# Type mmake -h for help.
|
|
#
|
|
#-----------------------------------------------------------------------------#
|
|
|
|
# IMPORTANT: the manpage is produced automatically from this help message,
|
|
# so if you change the help message, don't forget to check that
|
|
# the manpage still looks OK.
|
|
Help="\
|
|
Name: mmake -- Mercury Make
|
|
Usage: mmake [<mmake options>] [-- <make options>] <target>...
|
|
Options:
|
|
--use-mmc-make:
|
|
Use \`mmc --make' to build Mercury targets.
|
|
Implies \`--use-subdirs'.
|
|
--use-subdirs:
|
|
Build intermediate files in a \`Mercury' subdirectory,
|
|
rather than in the current directory.
|
|
(If the current directory already contains a \`Mercury'
|
|
subdirectory, then this option is the default.)
|
|
--target c:
|
|
Compile to C. This is the default."
|
|
Help="${Help}
|
|
--mercury-standard-library-directory <directory>
|
|
--mercury-stdlib-dir <directory>:
|
|
The directory containing the installed Mercury standard library.
|
|
--no-mercury-standard-library-directory, --no-mercury-stdlib-dir:
|
|
Don't use an installed Mercury standard library.
|
|
-s, --save-makefile:
|
|
Save the generated makefile to \`Mmake.makefile'.
|
|
This is useful for tracking down syntax errors in your Mmakefile.
|
|
-f <filename>, --file <filename>:
|
|
Use the specified file as the Mmake file.
|
|
-v, --verbose:
|
|
Print verbose progress messages.
|
|
-w-, --no-warn-undefined-vars:
|
|
Normally Mmake will warn about variables which are used
|
|
but not defined. This option disables that warning.
|
|
(The warning is never enabled when doing \`mmake clean'
|
|
or \`mmake depend' or the like, to avoid spurious warnings
|
|
when the dependencies have not yet been made.)
|
|
-h, --help:
|
|
Print this usage message.
|
|
Targets:
|
|
<module>.depend:
|
|
Make the files \`<module>.dep' and \`<module>.dv'.
|
|
This step is required in preparation for the targets below.
|
|
<module>:
|
|
Compile and link a Mercury program with main module
|
|
\`<module>.m' to produce an executable.
|
|
clean:
|
|
Remove intermediate files.
|
|
realclean:
|
|
Remove all automatically-generated files: intermediate files,
|
|
dependency files, and executables.
|
|
"
|
|
|
|
MERCURY_CONFIG_DIR=${MERCURY_CONFIG_DIR-${MERCURY_STDLIB_DIR-@CONFIG_LIBDIR@}}
|
|
MERCURY_STDLIB_DIR=${MERCURY_STDLIB_DIR-@LIBDIR@}
|
|
MMAKE_MAKE=${MMAKE_MAKE=@GNU_MAKE@}
|
|
MERCURY_DEFAULT_GRADE=${MERCURY_DEFAULT_GRADE=@DEFAULT_GRADE@}
|
|
MKTEMP=@MKTEMP@
|
|
TMPDIR=${TMPDIR=/tmp}
|
|
|
|
# Set the MACOSX_DEPLOYMENT_TARGET environment variable if needed.
|
|
@SET_MACOSX_DEPLOYMENT_TARGET@
|
|
|
|
MMAKE="$0"
|
|
include_makefile=
|
|
verbose=false
|
|
save_makefile=false
|
|
if test -d Mercury
|
|
then
|
|
use_subdirs=${MMAKE_USE_SUBDIRS=yes}
|
|
else
|
|
use_subdirs=${MMAKE_USE_SUBDIRS=no}
|
|
fi
|
|
use_mmc_make=${MMAKE_USE_MMC_MAKE=no}
|
|
warn_undefined_vars=true
|
|
|
|
while test "$#" -gt 0
|
|
do
|
|
case "$1" in
|
|
-h|--help)
|
|
echo "${Help}"
|
|
exit 0
|
|
;;
|
|
--use-subdirs)
|
|
use_subdirs=yes
|
|
shift
|
|
;;
|
|
--no-use-subdirs)
|
|
use_subdirs=no
|
|
shift
|
|
;;
|
|
--use-mmc-make)
|
|
use_mmc_make=yes
|
|
shift
|
|
;;
|
|
--no-mmc-make)
|
|
use_mmc_make=no
|
|
shift
|
|
;;
|
|
--target)
|
|
case "$2" in
|
|
c)
|
|
;;
|
|
*) echo "$0: invalid argument to" "\`--target' option" 1>&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift; shift
|
|
;;
|
|
-s|--save-makefile)
|
|
save_makefile=true
|
|
MMAKE="${MMAKE} $1"
|
|
shift
|
|
;;
|
|
-s-|--no-save-makefile)
|
|
save_makefile=false
|
|
MMAKE="${MMAKE} $1"
|
|
shift
|
|
;;
|
|
-f|--file)
|
|
mmake="$2"
|
|
shift
|
|
shift
|
|
;;
|
|
-v|--verbose)
|
|
verbose=true
|
|
MMAKE="${MMAKE} $1"
|
|
shift
|
|
;;
|
|
-v-|--no-verbose)
|
|
verbose=false
|
|
MMAKE="${MMAKE} $1"
|
|
shift
|
|
;;
|
|
-w|--warn-undefined-vars)
|
|
warn_undefined_vars=true
|
|
shift
|
|
;;
|
|
-w-|--no-warn-undefined-vars)
|
|
warn_undefined_vars=false
|
|
shift
|
|
;;
|
|
--include-makefile)
|
|
# XXX check that $2 exists first
|
|
MMAKE="${MMAKE} $1 $2"
|
|
include_makefile="${include_makefile} $2"
|
|
shift
|
|
shift
|
|
;;
|
|
|
|
--mercury-standard-library-directory|--mercury-stdlib-dir)
|
|
MERCURY_STDLIB_DIR="$2"
|
|
MERCURY_CONFIG_DIR="$2"
|
|
shift
|
|
;;
|
|
--no-mercury-standard-library-directory|--no-mercury-stdlib-dir)
|
|
unset MERCURY_STDLIB_DIR
|
|
unset MERCURY_CONFIG_DIR
|
|
;;
|
|
|
|
--mercury-config-directory-directory|--mercury-config-dir)
|
|
MERCURY_CONFIG_DIR="$2"
|
|
shift
|
|
;;
|
|
# We don't allow `MERCURY_CONFIG_DIR' to be unset
|
|
# without `MERCURY_STDLIB_DIR' also being unset.
|
|
|
|
--)
|
|
MMAKE="${MMAKE} $1"
|
|
shift
|
|
break
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# With `mmc --make' we need to use subdirs to avoid make trying to
|
|
# use Mmake rules to build the `.o' files for Mercury modules.
|
|
case "${use_mmc_make}" in
|
|
yes)
|
|
use_subdirs=yes
|
|
;;
|
|
esac
|
|
|
|
if test "${MERCURY_CONFIG_DIR}" != ""
|
|
then
|
|
MMAKE_DIR=${MMAKE_DIR=${MERCURY_CONFIG_DIR}/mmake}
|
|
export MERCURY_CONFIG_DIR
|
|
export MERCURY_STDLIB_DIR
|
|
fi
|
|
|
|
case "${MMAKE_DIR}" in
|
|
"")
|
|
echo "mmake: MMAKE_DIR not set"
|
|
exit 1
|
|
;;
|
|
*)
|
|
MMAKE_VARS=${MMAKE_VARS=${MMAKE_DIR}/Mmake.vars}
|
|
MMAKE_RULES=${MMAKE_RULES=${MMAKE_DIR}/Mmake.rules}
|
|
;;
|
|
esac
|
|
|
|
if test "${mmake}" = ""
|
|
then
|
|
if test "${MMAKEFILE}" = ""
|
|
then
|
|
if test -f Mmakefile
|
|
then
|
|
MMAKEFILE="Mmakefile"
|
|
else
|
|
if test -f Mmake
|
|
then
|
|
MMAKEFILE="Mmake"
|
|
else
|
|
MMAKEFILE=""
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
MMAKEFILE="${mmake}"
|
|
fi
|
|
|
|
case "${use_subdirs}" in
|
|
no)
|
|
dvs="`echo *.dv`"
|
|
if test "${dvs}" = "*.dv"
|
|
then
|
|
dvs=""
|
|
fi
|
|
deps="`echo *.dep`"
|
|
if test "${deps}" = "*.dep"
|
|
then
|
|
deps=""
|
|
fi
|
|
ds="`echo *.d`"
|
|
if test "${ds}" = "*.d"
|
|
then
|
|
ds=""
|
|
fi
|
|
;;
|
|
yes)
|
|
dvs="`echo Mercury/deps/*.dv`"
|
|
if test "${dvs}" = "Mercury/deps/*.dv"
|
|
then
|
|
dvs=""
|
|
fi
|
|
deps="`echo Mercury/deps/*.dep`"
|
|
if test "${deps}" = "Mercury/deps/*.dep"
|
|
then
|
|
deps=""
|
|
fi
|
|
ds="`echo Mercury/ds/*.d`"
|
|
if test "${ds}" = "Mercury/ds/*.d"
|
|
then
|
|
ds=""
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
MMAKE_USE_SUBDIRS=${use_subdirs}
|
|
MMAKE_USE_MMC_MAKE=${use_mmc_make}
|
|
|
|
if "${save_makefile}"
|
|
then
|
|
tmp=Mmake.makefile
|
|
else
|
|
case "${MKTEMP}" in
|
|
"")
|
|
old_umask=`umask`
|
|
umask 022
|
|
try=0
|
|
until
|
|
mmake_tmpdir=${TMPDIR}/mmake$$-${try}
|
|
tmp=${mmake_tmpdir}/mmake
|
|
trap 'rmdir ${mmake_tmpdir} >/dev/null 2>&1; exit 1' \
|
|
1 2 3 13 15
|
|
mkdir ${mmake_tmpdir}
|
|
do
|
|
try=`expr ${try} + 1`
|
|
# Give up after 20 tries.
|
|
case ${try} in
|
|
20)
|
|
echo "mmake: unable to create directory" \
|
|
"for temporary makefile" 1>&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
trap 'status=$?; rm -rf ${mmake_tmpdir}; exit ${status}' \
|
|
0 1 2 3 13 15
|
|
umask ${old_umask}
|
|
;;
|
|
*)
|
|
# mktemp should give its own error message.
|
|
tmp=`${MKTEMP} ${TMPDIR}/mmake.XXXXXX` || exit 1
|
|
trap 'status=$?; rm -f ${tmp}; exit ${status}' 0 1 2 3 13 15
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
MMAKE_MAKE_CMD="${MMAKE_MAKE} -f ${tmp} -r"
|
|
|
|
# Enable checking for undefined variables -- but not when making the
|
|
# dependencies, or when cleaning up, because in either of those two cases
|
|
# the dependencies might not have been made yet, so there may be
|
|
# lots of undefined variables.
|
|
case "$@" in
|
|
dep*|*' dep'*|*.dep*|*clean*)
|
|
MMAKE_MAKE_OPTS=""
|
|
;;
|
|
*)
|
|
case "${warn_undefined_vars}" in
|
|
true)
|
|
MMAKE_MAKE_OPTS="--warn-undefined-variables"
|
|
;;
|
|
false)
|
|
MMAKE_MAKE_OPTS=""
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
|
|
if "${verbose}"
|
|
then
|
|
echo MMAKE=${MMAKE}
|
|
echo export MMAKE
|
|
echo MMAKE_MAKE_CMD=${MMAKE_MAKE_CMD}
|
|
echo export MMAKE_MAKE_CMD
|
|
echo MMAKE_USE_SUBDIRS=${MMAKE_USE_SUBDIRS}
|
|
echo export MMAKE_USE_SUBDIRS
|
|
echo MMAKE_USE_MMC_MAKE=${MMAKE_USE_MMC_MAKE}
|
|
echo export MMAKE_USE_MMC_MAKE
|
|
echo MERCURY_DEFAULT_GRADE=${MERCURY_DEFAULT_GRADE}
|
|
echo export MERCURY_DEFAULT_GRADE
|
|
echo MMAKEFILE=${MMAKEFILE}
|
|
echo export MMAKEFILE
|
|
echo cat ${MMAKE_VARS} ${include_makefile} ${MMAKEFILE} \
|
|
${ds} ${dvs} ${deps} ${MMAKE_RULES}">>" ${tmp}
|
|
echo ${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} -f ${tmp} -r "$@"
|
|
fi
|
|
export MMAKE
|
|
export MMAKE_MAKE_CMD
|
|
export MMAKE_USE_SUBDIRS
|
|
export MMAKE_USE_MMC_MAKE
|
|
export MERCURY_DEFAULT_GRADE
|
|
export MMAKEFILE
|
|
# XXX The ${dvs} and ${ds} variables can be so long as to overflow size limits
|
|
# on command lines, so we use xargs. Echo doesn't quote the file names
|
|
# correctly, but this is not a problem in practice because none of our
|
|
# file names contain any special characters.
|
|
# If this is fixed, then that fix needs to be replicated in one of the modules
|
|
# that has been carved out of modules.m over the years.
|
|
# XXX There should only be one .dv file per program, just like there should be
|
|
# just one .dep file per program, so the value of ${dvs} should NOT overflow
|
|
# any limits. However, since there should be one .d file per MODULE,
|
|
# ${ds} definitely CAN overflow command line length limits.
|
|
{
|
|
cat ${MMAKE_VARS}
|
|
echo ${dvs} | xargs cat
|
|
echo ${include_makefile} ${MMAKEFILE} | xargs cat
|
|
echo 'ifneq ($(MMAKE_AUTO_INCLUDE_DS),no)'
|
|
echo ${ds} | xargs cat
|
|
echo 'endif'
|
|
cat ${deps} ${MMAKE_RULES}
|
|
} > ${tmp}
|
|
|
|
if test "${MMAKE_DEBUG}" != ""
|
|
then
|
|
MMAKE_DEBUG_OPTS="--debug=${MMAKE_DEBUG}"
|
|
else
|
|
MMAKE_DEBUG_OPTS=""
|
|
fi
|
|
|
|
case "$#" in
|
|
# Note that we can't use `exec' here, because if we did that,
|
|
# that `trap' code which removes ${tmp} would never get executed.
|
|
0)
|
|
${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} ${MMAKE_DEBUG_OPTS} -f ${tmp} -r
|
|
;;
|
|
*)
|
|
${MMAKE_MAKE} ${MMAKE_MAKE_OPTS} ${MMAKE_DEBUG_OPTS} -f ${tmp} -r "$@"
|
|
;;
|
|
esac
|