What follows depends on autoconf
, so we're assuming you're working off of a git
clone of the server sources rather than a tarball (since you wouldn't be here unless you were interested in developing new features and for that you need git
; autoconf
you do not necessarily have to learn too much about; we just need you to be running a recent version).
We will also assume you have successfully cloned the MOO server source directory and done autoconf && ./configure -C && make
to build a vanilla server. (If you hadn't actually done -C
, that's okay, just rerun the configure script as ./configure -C
; it should be a fast no-op. Also make
again, too, if you want, but that should also be a fast no-op.)
(... also hoping you have an editor that does syntax highlighting so that #
and dnl
comments look right? Emacs has anautoconf
mode that is different from its m4
mode and you should use the former when editing both .ac
and .m4
files in this source tree. See below for further Emacs tips)
In what follows, $
at the beginning of the line is intended to be a shell prompt -- yes, real world people will display current directories and other things that are all irrelevant for what we're doing. You'll be staying in the root MOO source directory throughout.
Here is a quick convenience command you can set up:
$ mooval() {
printf "%s\n" ";$1" 'abort' |
./moo -e -l /dev/null Minimal.db /dev/null |
sed -e '0,/^[*]/d;/^MOO.*Bye.*NOT saving/,$d;/^$/d'
}
(Cutting&pasting everything after the $
is probably your best bet here. Or just save it to a file and source it from there (i.e., using the .
command). And yes, we're assuming you have a modern Unix shell that understands shell functions; any of bash
, ksh
, zsh
, or dash
will do. Otherwise, you will need to write an equivalent shell script yourself and store it on your PATH
somewhere (sorry)).
As you might guess, mooval
runs a server, loads Minimal.db, redirects both log and checkpoints to nowhere, fires up Emergency Wizard Mode, evals the first argument, shows you the result, and then exits without trying to save anything:
Here are, respectively, what successful evaluations and errors look like in this world:
$ mooval 'server_version("features")'
MOO (#3): => {"regexp"}
$ mooval 'hello()'
MOO (#3): ** 1 errors during parsing:
Line 2: Unknown built-in function: hello
and just always put single quotes around that first argument; it means everything in between will be passed by the shell verbatim and MOO almost never uses single quotes for anything, so this is about as ideal as it gets.
(And yes, this version of mooval
is quite simplistic. Doubtless, you can already see multiple ways to improve or confuse it, all entirely beyond the scope of this document.)
Copy the file extensions_tutorial.ac to extensions2.ac
(which,
whenever it exists, is automatically hooked into the build process
the way extensions.ac
is, but there's no penalty for it not
existing.)
Important
When you are done with this tutorial, be sure to delete or rename
extensions2.ac
and then do one lastautoconf -f
to flush out whatever effects it's had. Otherwise it lingers.
Visit extensions2.ac
; it's nothing but comments and is where
we'll be doing most of our edits. You should probably take a moment
to read through the comments.
You may notice that the "TOP" section is entirely within square
brackets [
]
, which, in this edition of m4
, are the quote
characters , which means m4
strips off the outer pair of brackets
(yes they have to nest properly) and sends everything between verbatim
as an argument to whatever the context is, in this case, we're in the
middle of a (gigantic, taking up the entire file) invocation of
MOO_XT_DECLARE_EXTENSIONS
which interprets its first argument as
being in MOO_XT
this weird, idiosyncratic, domain-specific language
I made up.
Here, indentation (of noncommented lines) matters. Exact amounts don't matter so much as "indented less" vs. "indented the same" vs. "indented more".
And by "same", I mean "same sequence of tab and space characters".
Also, tabs have to come first, trying to indent in any other way will give you a "spaces before tabs" error).
(Actually, life will be generally easier if you never use tabs in this file, but, for the tutorial's sake, I wanted the commented and uncommented lines to match up with each other to make it more readable so I'm doing that just this once (promise))
(And yes, the "MIDDLE" and "BOTTOM" sections work differently.
Really, they're just straight m4
code).
Okay, enough talk. Let's do stuff:
In the "TOP" section, uncomment the %%extension hello
line,
(it tells you how to do this).
Also, save the file. (Since this will get old quickly, I'll assume from now on I don't have to keep telling you save the file after every change.)
Rerun autoconf -f && ./configure -C && make
(You may want to alias this to something short since you'll be
typing it a lot. From now on, I'm just going to say "Rebuild")
(as for why the -f
: This makes autoconf
re-read things it
would normally skip if it has reason to believe they don't
matter, and since ./configure
already has weird dependency
rules due to Makefile
itself needing to be rebuilt whenever
./configure
or anything else in Autoconf Land changes, and the
GNU folks having come up with extra-clever ways for Makefile to
behave in situations when it's rebuilding itself, and trying to
come up with a way to not include extensions2.ac
in the
distribution, but have ./configure
both depend on
extensions2.ac
, but quietly skip over it not being there so
as not to confuse all of the People Who Are Not Writing
Extensions (which is at least 7 billion more than the People
Who Are Writing Extensions), without causing random, extra
unnecessary runs of ./configure
was all making my head explode,
all to cover situations that are normally quite rare, so I
punted. Yes, that was all one sentence.
The rule is specific to extensions2.ac
and it's simple:
If you edit this file, you need to do autoconf -f
. Done.)
You should now be able to do this:
$ mooval 'server_version("features")'
MOO (#3): => {"regexp", "hello"}
In other words, there is now a hello
extension. Feel free to look
at how configure
and version_src.h
changed. The extension does
absolutely nothing, but it is, at least, listed now.
It is also a mandatory extension, i.e., always active, because there is as yet no way to disable it.
%disabled
line. Rebuild.$ mooval 'server_version("features")'
MOO (#3): => {"regexp"}
So you made the extension go away again. Congratulations.
Actually, this is important: Whatever you do, make sure you're cleaning up after yourself, so that when your extension is disabled, your impact on the existing code is zero. Yes, I know I may have violated that rule a bit for Unicode, but ... Unicode, so... Point is, the less you're doing when your extension is disabled, the more The People Who Hate Your Extension will thank you.
%disabled
line. Rebuild.$ mooval 'server_version("features")'
MOO (#3): => {"regexp", "hello"}
Surely, there's some better way to turn it off and on. Perhaps a command line argument?
$ ./configure -C --disable-hello
configure: WARNING: unrecognized options: --disable-hello
...
$ ./configure -C --enable-hello
configure: WARNING: unrecognized options: --enable-hello
...
Evidently not, but maybe we can fix this?
--enable-hello
line in extensions2.ac
and rebuild.Oh, look:
$ mooval 'server_version("features")'
MOO (#3): => {"regexp", "hello"}
$ ./configure -C --disable-hello && make
...
configure: (%%extension hello:) disabled
...
$ mooval 'server_version("features")'
MOO (#3): => {"regexp"}
$ ./configure -C --enable-hello && make
...
$ mooval 'server_version("features")'
MOO (#3): => {"regexp", "hello"}
No message the second time because enabled is the default. And, yay, our extension is back.
And, in case you were wondering, the name of the extension and the
name for the --enable-
argument do not have to be the same.
--enable-hello
, uncomment --enable-hi
,
and rebuild with ./configure -C --disable-hi
Still kind of annoying that ./configure -hs
says nothing about it.
But then, we haven't specifed what it should say, so how could it know?
Uncomment the two lines (%?
and %?-
) that are immediately after
--enable-hi
. These are indented more, meaning they are
subdirectives of --enable-hi
.
Rebuild.
And,... oh look, now we have argument descriptions:
$ ./configure -hs
...
--disable-hi no hello() function, sorry
--enable-hi provide a hello() function
If you are annoyed that these two lines are mushed in with other options (it sort of looks like they're part of the Waifs package), we can fix that by adding a section header:
%?
, the one that has the same
indentation as --enable-
; it is a sibling directive and actually
applies to the entire extension, saying in effect, "This extension
has so much crap under it, it needs its own section header".
Rebuild.And now we get to see:
$ ./configure -hs
...
Hello Facilities:
--disable-hi no hello() function, sorry
--enable-hi provide a hello() function
At this point, it's natural to think there should be some way to
actually provide, say, a hello()
function. So let's do that.
Recomment everything except the %%extension
line,
so that we're back to the mandatory invisible extension
we had as of step 4.
Then, create a file hello.c
with this in it:
/* #include "hello.h" */
#include "bf_register.h"
#include "config.h"
#include "options.h"
#include "functions.h"
#include "storage.h"
static package
bf_hello(Var arglist UNUSED_, Byte next UNUSED_,
void *vdata UNUSED_, Objid progr UNUSED_)
{
const char *msg =
#if HELLO_ESMTP
"ehlo world"
#else
"hello world"
#endif
;
return make_string_pack(str_dup(msg));
}
void
register_hello(void)
{
register_function("hello", 0, 0, bf_hello);
}
For now, assume this code works (it should!). I could go into how
builtin functions work, what a package
is, why you need that
str_dup()
call, and so on, but this is described elsewhere.
The question here is how to get make
and friends to do the right
things and get this compiled in:
XT_CSRCS = hello.c
line and rebuild.For this one, you should look at what happens to Makefile
and
bf_register.{h,c}
.
Extension commands of the form "VAR=
value" refer to Makefile
variables. In most cases where the VAR is something random, this line
will just get copied in when the extension is active (when you need
your own special makevars to make life easier in other parts of your
extensions, not that you'll need to do this that often).
But certain VARs are special to the extension framework: XT_CSRCS
is the list of C sources that each extension potentially adds to. In
other words, XT_CSRCS
is going to list all of the extra C source
files needed by all active extensions, not just hello
. (And if we
were to need to have a hello.h
-- we do not in this version of the
world -- that's what XT_HDRS
is for).
And then all C sources, both the common ones and the "XT" ones,
(always) get scanned for registration functions -- read
bf_register.h
if you care about how that works -- which then show up
in bf_register.{h,c}
. Which is then how the server knows to invoke
register_hello()
on startup.
Which means this should all now Just Work:
$ mooval 'server_version("features")'
MOO (#3): => {"regexp", "hello"}
$ mooval 'hello()'
MOO (#3): => "hello world"
Now, as it happens, hello.c
has some Optional Behavior,
i.e., there appear to be multiple conflicting paradigms for what
hello()
should actually do. And so, we have an Option,
HELLO_ESMTP
, which presumably gets #define
d somewhere.
In times of yore, Pavel would just add a suitable default
#undef HELLO_ESMTP
to options.h
, provide a description,
and if you wanted to change it, you'd edit that file manually.
Here in The Future, we are More Advanced:
options.h.in
somewhere before the
#include "options_epilog.h"
that ends everything there (and you
can have the comment say anything you want because we don't
care)./************************************************************
* The HELLO_ESMTP option is an important component of the
* Hello extension. If #defined, it makes the new builtin
* hello() behave in a more ESMTP-ly fashion
*/
#undef HELLO_ESMTP
and it's #undef
not because that's the default but because everything in options.h.in
needs to be #undef
.
Normally, the actual default would have to be set in options.ac
,
however since this option is essentially useless without the extension,
we'd just as soon keep this information in the same file with
the extension description.
You'll notice that options.ac
consists entirely of a single call to
MOO_DECLARE_OPTIONS
, which is an m4
macro that can actually be
invoked multiple times.
So that is what the "MIDDLE" section of extensions2.ac
(also
extensions.ac
, for that matter) is.
MOO_DECLARE_OPTIONS
by deleting
the characters dnl
from the beginning of the line.$ autoconf -f && ./configure -hs
...
--enable-def-HELLO_ESMTP make hello() do The ESMTP Thing
$ ./configure -C --enable-def-HELLO_ESMTP && make
...
$ mooval 'hello()'
MOO (#3): => "ehlo world"
But really this is all MOO_DECLARE_OPTIONS
at work. This is how you make a regular option and the only thing we're doing differently is that the MOO_DECLARE_OPTIONS
invocation is not the one that's in options.ac
. Thus far, MOO_XT_DECLARE_EXTENSIONS
is not seeing any of this.
We haven't even put the --enable-hi
argument back.
But maybe this is enough.
Or maybe, once we get back to the release situation where this extension is disabled by default, and people start getting annoyed that they have to do both --enable-hi
and --enable-def-HELLO_ESMTP
in order to get what they want. We can do something to make their lives easier?
Time for some option keywords.
Uncomment --enable- hi = KWD
and the next two lines (%?-
, %?
).
This brings back --enable-hi
and adds a bit more to tell people they
can add keywords if they want (they don't have to).
Then uncomment %option esmtp...
, and the next two lines
(%alt
and %?
).
Finally, to make it all look truly professional, we will put back the
%? Hello Facilities:
section header as well.
And voilà!
$ autoconf -f && ./configure -hs
...
Hello Facilities:
--disable-hi no hello() function, sorry
--enable-hi=KWD,... provide a hello() function
ehlo|esmtp: . . do the esmtp thing
...
$ ./configure -C --enable-hi=ehlo && make && mooval 'hello()'
...
MOO (#3): => "ehlo world"
$ ./configure -C --enable-hi=esmtp && make && mooval 'hello()'
...
MOO (#3): => "ehlo world"
$ ./configure -C --enable-hi && make && mooval 'hello()'
...
MOO (#3): => "hello world"
$ ./configure -C --disable-hi && make && mooval 'hello()'
...
MOO (#3): ** 1 errors during parsing:
Line 2: Unknown built-in function: hello
Congratulations, you've completed the tutorial and earned your Extensions White Belt. Go forth, and remember: With great power comes great responsibility.
If you want to learn more from this (meaning the following is all optional, but really good if you can manage it), you can visit configure
, Makefile
, config.status
,config.h
,options.h
,bf_register.c
, and version_src.h
in Emacs buffers, and then repeat as much of the tutorial as you can manage, but, this time:
After each rebuild, you diff the various buffers with what they've been been replaced with on-disk to see what got changed, then revert the buffers to ready them for the next command. Just so that you know,
autoconf
writes configure
./configure
writes Makefile
, config.status
,config.h
, and options.h
make
writes bf_register.c
, and version_src.h
This is actually relatively easy to set up in Emacs if you
load my bdiff.el
package, which has
M-x bdiff
(compare a buffer with its disk file),M-x list-munged-buffers
(list buffers whose files were changed outside of Emacs),M-x Buffer-Menu-bdiff
(bound to c
; invokes bdiff
from buffer listing)M-x Buffer-Menu-revert
(bound to R
; reverts buffer from the buffer listing)(I wrote this rather a long time ago; someone may have something better, now.)
And then you
(setq bdiff-reverse-p t)
to make bdiff
treat the disk file as
the newer one (rather than the older one as it usually does), and
set a post-compilation hook
(defun c-f-show-munged (&rest r)
(call-process "sh" nil '(:file "configure-hs.out") nil "-c" "./configure -hs")
(list-munged-buffers))
(add-hook 'compilation-finish-functions 'c-f-show-munged)
(where you also want a buffer visiting configure-hs.out
so you can watch that, too)
do (remove-hook 'compilation-finish-functions 'c-f-show-munged)
when you are done with this; otherwise it's going to get annoying.
(for now, you have examples in extensions.ac)
TODO
TODO
Here are all of the cmds.
The source that actually does the work is in ac_include/ax_xt.m4.
Declares an --enable-
argument for ./configure
for the parent
%%extension
. The expected format is
--enable-
ew_name=
keywords, where keywords is a
comma--separated list indicating which subfeatures are being chosen,
the individual possible keywords being declared via %option
or
%option_set
(to have a single keyword that selects multiple
subfeatures).
Declares a --with-
argument for ./configure
.
If the parent declaration is %require
, the expected format is
--with-
ew_name=
lib_keywords, where lib_keywords is a
comma--separated list of library keywords in preference order. The
default (yes
keyword) is to search for all of the libraries in order
declared.
If the parent declaration is %build
, the expected format is
--with-
ew_name=
directory_path, where ew_name, by convention,
is expected to end in path
(we don't enforce this yet, but maybe we
should), and directory_path indicates where the build directory is
to be found relative to the MOO source directory. This directory is
then assigned to the make variable specified by %dirvar
and also
substituted for %DIR%
in any %ac
code provided.
For %%extension
this determines the extension's cppname and/or its
various option cppnames. %cdefine
must precede all %option
declarations.
It is is intended that an AC_DEFINE
be issued for an extension
cppname exactly when the extension is active. Option cppnames are intended to be AC_DEFINE
d
if an option keyword is chosen either directly or indirectly (via
%option_set
) by the --enable-
ew_name argument. In either case,
if a given cppname is also defined in a MOO_DECLARE_OPTIONS
then
the corresponding --enable-def-
argument can override this
(... and if there's some reason that being able to override would be a
bad idea, that's then also a reason to not declare it in
MOO_DECLARE_OPTIONS
and instead put that cppname in config.h.in
instead of options.h.in
).
For %require
, this determines a requirement cppname and/or the
library cppnames. %cdefine
must precede all %lib
declarations.
An AC_DEFINE
for the requirement cppname is issued if and only if
the requirement has been satisfied, which must and can only happen
if the extension is active (if, say you want to do without having a
separate extension cppname). An AC_DEFINE
for a Library cppnames
is issued if the library is selected.
Important
There is currently no notion of being able to override library selections with
--enable-def-
. cppnames for libraries and requirements must go inconfig.h.in
.
There are actually 3 forms of this declaration:
%cdefine
cppname
Sets cppname as the cppname for the extension or requirement,
to be AC_DEFINE
d if the parent extension is active or if
the parent library requirement has been satisfied,
%cdefine
cppname%s_template
Creates a cppname for each option or lib by substituting the
%option
or %lib
cppname argument into cppname_template
(wherever the %s
is).
Note that for extensions, this form allows no way to create a cppname
for the extension. However, you can still set up an option keyword
that is %implied
by all of the others, which is functionally
the same thing
%cdefine
cppname value%s_template
Sets cppname as the cppname for the extension or requirement, to
be AC_DEFINE
d if the parent extension is active or if the parent
library requirement has been satisfied, where the value
in the case of a library, is the result of substituting library cppname into value_template, or
in the case of an option, is a bitwise or (|
) of the various
substitutions of option cppnames into valuetemplate correponding
to options that have been selected,
where, in either case, all of the possible substitution results need
to have been given suitable distinct power-of-2 integer values in
one of options_epilog.h
or config_epilog.h
, depending.
For either of the templated cases, the option or library cppname to be
substituted, if it is not specifed in the %option
or %lib
declaration,
defaults to the option or library keyword in all-caps.
In all cases you need to ensure that each possible cppname has an
#undef
line in one of config.h.in
or options.h.in
,
otherwise the C code won't see it.
Declares an extension.
Allowed subcmds are %?
, %disabled
, --enable-
, %cdefine
,
%option
, %option_set
, =
, and %require
.
In general, this adds helptext to configure -hs
.
%%extension
, creates an overall section header.--enable-
or --with-
,
describes what --enable-
_ew_name or --with-
_ew_name does.--option-
describes this option keyword.For --enable-
or --with-
,
describes what --disable-
ew_name or --without-
ew_name does.
Add a line of description to a --with-
.
Allowed in %lib
or %build
, this inserts the given m4_code,
which is expected to expand to shell code
For %lib
, the expansion executes in the library search loop.
Typical usage looks like
%ac AC_SEARCH_LIBS([[ble_func]], [[best_lib_evar]], [%USE%])
i.e., attempt to compile a small program calling ble_func()
using
-lbest_lib_evar
, and, if that succeeds, then whatever %USE%
expands to is invoked to indicate that this library is to be selected
(which then breaks out of the search loop).
The other available placeholder is %FAIL%
which is expected to
appear in an lvalue position (left side of an =
) getting assigned an
error message in a failure block. A list of the %FAIL%
messages for
all libraries is displayed if none of the libraries can be selected.
(If you invoke both %USE
and %FAIL%
, the library will be selected
and all %FAIL%
messages will be ignored.)
For %build
, the expansion shell code is executed if the build is
selected. In this case, %DIR%
is available as a placeholder that
expands to a shell code expression that evaluates to the build directory,
for situations where you need to investigate something about it for
./configure
purposes).
Quoting within m4_code should be such that placeholders will be
m4-expanded. E.g., do not do
%ac AC_SEARCH_LIBS([[f]], [[lib]], [[%USE%]])
.
Allowed in %require
, this inserts the given m4_code, which is
expected to expand to shell code to determine the default library
search list for when there is no --with-
ew_name argument or the
keyword given is an implicit or explicit yes
, for situations where
this needs to be determined dynamically depending on whether, e.g.,
other extensions are active or not.
The expansion is expected to either be a shell expression
that expands to a comma-separated list of library keywords
(as would be provided in --with-
ew_name=
) or a shell
command that assigns to the placeholder %LIB
.
Quoting within m4_code should be such that placeholders will be
m4-expanded. E.g., to protect uvw,xyz
from expansion
do %ac_yes AS_IF([...],[%LIB%[=uvw,xyz]],[%LIB%[=xyz]])
,
not %ac_yes AS_IF([...],[[%LIB%=uvw,xyz]],[[%LIB%=xyz]])
,
Specfies an alternate keyword for an %option
or %lib
.
Specfies a static build for a %lib
.
Allowed subcmds are --with-
, and %ac
, %make
, %dirvar
, %path
, and =
.
Required in %build
to specify the name of the make variable to be assigned the (absolute) build directory path
(whether this comes from --with-*path
or %path
).
Indicates that an extension is disabled by default. Otherwise it is enabled by default.
For %option
, indicates that other_keyword, which may be
a single option or a set thereof is implied by selecting
this option's keyword.
Declares a library choice for %require
with keyword and a
corresponding cppname as determined by cpp_keyword, which defaults
to keyword upcased, and the setting of %cdefine
.
Allowed subcmds are %ac
, %alt
, =
, and %build
For a %build
, declare the additional dependencies and recipes to be
included in Makefile
if this build is selected.
For an %%extension
, this declares a option set os_keyword that, if
selected, implies all of the right-hand-side keywords.
An %option_set
does not get a cppname.
For an %%extension
, this declares an option keyword and a
corresponding cppname as determined by cpp_keyword, which defaults
to keyword upcased, and the setting of %cdefine
.
Tip
Declaring an option keyword for an
--enable-
argument and declaring an option cppname foroptions.h
are not the same thing.
Allowed subcmds are %implies
, %?
, and %alt
.
Declares a fixed directory for %build
or a default directory for the
situation where --with-*path
has not been supplied by the user.
(Unless you're actually planning to this build directory as part of
the MOO distribution (please don't; I worked hard on getting rid of
these), this is really only recommended for development in order to
spare you from having to retype--with-whateverpath=path/to/your/build
over and over while you're working through the issues.)
Declares a requirement for an extension. Currently, the only supported notion of "requirement" is that of a required library that needs to be linked in order for the extension to function.
Allowed subcmds are --with-
, %cdefine
, %ac_yes
, and %lib
.
The order for the library search loop is specified by the
--with-
ew_name argument given by the user, which defaults to
yes
, which means whatever %ac_yes
says, unless there is no
%ac_yes
declaration, in which case it's order in which the %lib
declarations occur.
Allowed in %%extension
, %lib
or %build
.
The specified variable setting is included in Makefile
if the
extension is active, the library is selected, or the build is
selected, respectively.
Either this sets VAR to value or, in the case of variables special to the extension framework, appends value to whatever may already have already been added by other active extensions or selected libaries/builds, with either a space or a newline separator as appropriate for that VAR.
The following are the "standard" makevars that the extension framework currently knows about and makes substitutions in:
CPPFLAGS
which is really only needed for -I
options needed to
reference additional library headers or headers from a %build
directory
Warning
Putting
-D
inCPPFLAGS
for an extension is likely a mistake and you should instead consider adding a setting toconfig.h
oroptions.h
. (At the moment, unit tests and instrumentation builds are the only scenarios I can come up with where-D
makes more sense and you're not going to be making extensions out of those.)
LIBS
(prepend) System libraries (-lfoo
) needed by your extension;
these will be found and filled in by autoconf snippets
(what the %ac
and %ac_yes
directives are for).
Important
Any libraries or object files we need to
%build
ourselves and statically link go inXT_LOBJS
, notLIBS
.
XT_CSRCS
.c
source files present/compiled-in only if the extension is
active ($(XT_CSRCS:.c=.o)
is automatically included in OBJS
)
XT_HDRS
.h
headers used if the extension is active (admittedly, the .h
groupings may not matter so much since .d
files are now built
automatically to take care of dependencies by -MMD -MP
and lists of
headers are really only needed for the tarball.)
XT_LOBJS
(prepend) Libraries or external .o
files that come from separate
build directories with their own Makefiles, but need to be included
in our build process
XT_DIRS
list of build directories (for targets like make clean-all
that
need to descend into them). Relative paths appearing in XT_DIRS
are always with respect to $(abs_srcdir)
in order to make VPATH
builds work.
Important
XT_DIRS
cannot actually be set directly. Use%path
(to use a hardwired directory) or the combination of--with-*path
and%dirvar
(to get the directory from an argument).
There are also two additional Makefile substitutions which also cannot be set directly, start out empty, and get lines appended to them depending on which extensions are active
@XT_MAKEVARS@
Makefile variable definitions other than those above -- which
extension authors should feel free to use to simplify whatever
they're doing in the other makefile vars and rules -- are added here.
@XT_RULES@
This collects everything appearing in %make
directives
for extensions, including but not limited to
XT_LOBJS
items-MMD -MP
won't findThe rule for building the server is then
moo: $(OBJS) $(XT_LOBJS)
$(CC) $(LDFLAGS) $(OBJS) $(XT_LOBJS) $(LIBS) -o $@
while individual modules depend on CPPFLAGS
and CFLAGS
in the usual way.
So, a cppname can either appear in config.h
or options.h
.
As far as ./configure
is concerned, there is no distinction between
these files. A cppname for which an AC_DEFINE
has been issued
(due to ./configure
deciding it needs a value) will have its
#undef
line either substituted with a #define
to put in a value
or commented out to indicate it should stay #undef
, wherever it appears;
whether that's config.h.in
or options.h.in
doesn't matter.
Both files are declared with AC_CONFIG_HEADERS
in configure.ac
;
autoconf
would allow us to have ten more such files if we wanted.
There are multiple ways to draw a distinction and they won't always completely agree:
In the old days we had settings that ./configure
did automatically
in config.h
and settings the user did by hand in options.h
.
And even if we want to let ourselves be confused by ./configure
doing everything now, there's still a distinction between
and it's not that huge difference whether we're making someone manually
edit a file vs. making them type --enable-def-OPTIONNAME
,
even if some of the settings in options.h
really should not
be touched.
autoconf
draws a distinction between
--enable-FEATURE
arguments that are there to "allow users to
choose which optional features to build and install" vs.--with-PACKAGE
arguments "to specify which external software
packages to use" (i.e., of some set of packages that presumably
serve the same purpose; the examples they give are using a
different linker or using a different window system).These somewhat line up with the previous distinction if you think
about the ideal world where a user really should not care which
packages are being used, the question of which is best being an
implementation detail of the sort that the super-smart version of
./configure
that we don't have yet would be able to figure out
on its own.
So you could then take the stance that --with-
arguments are
"implementation choices we're helping ./configure
with because
it's not smart enough yet" vs. --enable-
being feature choices we
actually care about.
... from which you then get this vague sense that "--with-
things
go in config.h
" while "--enable-
things go in options.h
,
which is a possible way to organize things, even if, historically,
that's not how this was done and there are any number of matters
that are decided in options.h
because someone put them there at
some point, because once-upon-a-time it was the only place to put
such things, and it would now be painful to move them.
The actual distinction goes something like this:
There is a set of high-level choices one needs to make up front. E.g., are we doing Unicode or not?
If we are, then ./configure
has work to do; in this case, there's
an extra source module that needs to be compiled in, we need to
find a Unicode character data (uclib
) library, and so on.
Later, there are some low-level choices that can be made, e.g.,
what are we doing about identifiers in verbcode? are we allowing
non-ASCII there? This low level choice is just an #ifdef
;
the code is all there for either version of the world.
Therefore we can allow UNICODE_IDENTIFIERS
to be an option,
i.e., a genuine options.h
option, where the user can use
--enable-def-UNICODE_IDENTIFIERS
to set it or not,
and it'll work either way.
On the other hand, we have UNICODE_STRINGS
, which answers
the question of whether we have arbitrary UTF-8 in our string
constants.
Which is a pervasive thing.
That is, once we decide we are not going to have Unicode, no
amount of #ifdef
-ing is going to make the code and libraries
that ./configure
should have installed magically appear.
Thus, allowing the user to change UNICODE_STRINGS
after the fact
is going to fail horribly and shouldn't be allowed.
Therefore, UNICODE_STRINGS
belongs in config.h
.
It is not an option, it's a setting that ./configure
does
automatically, even if it happens to be based on our high-level
feature choice, we don't get a further choice to change it back.
... even though it is an %option
keyword according to
extensions.ac
, being part of the original high-level choice
whether to do Unicode.
The extensions framework creates a number of cppnames.
All of the ones at the %require
level and below have to go
in config.h
.
The rest are created by %option
declarations, in which case you (the
extension developer) have a choice whether they can/should be set
separately later by --enable-def
.
If you decide not to allow this for a particular cppname,
you put it in config.h.in
and you're done.
If you're okay with people messing with it independently, then you
options.h.in
,MOO_DECLARE_OPTIONS
line, in which case
[bool]
or [int]
(for bitmasks) andno
What's going on here is the extension framework gets first
crack at setting it, so that's where the real default
value lives.