Files
mercury/scripts/mmake.in
Zoltan Somogyi 1296ec11e5 Partially clarify and partially fix d_file_deps.
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.
2025-08-11 10:51:29 +02:00

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