📄 autoupdate.in
字号:
# ----------- # Called at the end of all the obsolete macros. Disable the # builtins, and m4sugar if needed.. _au_define([_au_disable], [_au_popdef([_au_enabled])_au_dnl _au_ifdef([_au_enabled], [], [__au_disable()])]) ## ------------------------------- ## ## Disable, and process the file. ## ## ------------------------------- ## _au_divert(-1) # Disable m4: M4sugar and the AC autoquoting macros are not loaded yet, # hence invoking `_au_disable' is wrong. _au_include([unm4.m4]) # Disable special characters. _au_changequote() _au_changecom() _au_divert(0)_au_dnlEOF $input_m4 =~ s/^ //mg; # prepared input -- input, but reenables the quote before each AU macro. open INPUT_M4, ">$tmp/input.m4" or error "cannot open: $!"; open FILE, "<$file" or error "cannot open: $!"; print INPUT_M4 "$input_m4"; while (<FILE>) { eval $au_changequote; print INPUT_M4; } close FILE or error "cannot close $file: $!"; close INPUT_M4 or error "cannot close $tmp/input.m4: $!"; # Now ask m4 to perform the update. xsystem ("$m4 --include=$tmp" . join (' --include=', '', reverse (@prepend_include)) . join (' --include=', '', @include) . " $tmp/input.m4 >$tmp/updated"); update_file ("$tmp/updated", "$file" eq "$tmp/stdin" ? '-' : "$file"); }exit 0;# ## ---------------------------- ### ## How `autoupdate' functions. ### ## ---------------------------- #### The task of `autoupdate' is not trivial: the biggest difficulty being# that you must limit the changes to the parts that really need to be# updated. Finding a satisfying implementation proved to be quite hard,# as this is the fourth implementation of `autoupdate'.## Below, we will use a simple example of obsolete macro:## AU_DEFUN([OLD], [NEW([$1, $2], m4_eval([$1 + $2]))])# AC_DEFUN([NEW], [echo "sum($1) = $2"])## the input file contains## dnl The Unbelievable Truth# OLD(1, 2)# NEW([0, 0], [0])## Of course the expected output is## dnl The Unbelievable Truth# NEW([1, 2], [3])# NEW([0, 0], [0])### # First implementation: sed# # =========================## The first implementation was only able to change the name of obsolete# macros.## The file `acoldnames.m4' defined the old names based on the new names.# It was simple then to produce a sed script such as:## s/OLD/NEW/g## Updating merely consisted in running this script on the file to# update.## This scheme suffers an obvious limitation: that `autoupdate' was# unable to cope with new macros that just swap some of its arguments# compared to the old macro. Fortunately, that was enough to upgrade# from Autoconf 1 to Autoconf 2. (But I have no idea whether the# changes in Autoconf 2 were precisely limited by this constraint.)### # Second implementation: hooks# # ============================## The version 2.15 of Autoconf brought a vast number of changes compared# to 2.13, so a solution was needed. One could think to extend the# `sed' scripts with specialized code for complex macros. But this# approach is of course full of flaws:## a. the Autoconf maintainers have to write these snippets, which we# just don't want to,## b. I really don't think you'll ever manage to handle the quoting of# m4 from sed.## To satisfy a., let's remark that the code which implements the old# features in term of the new feature is exactly the code which should# replace the old code.## To answer point b, as usual in the history of Autoconf, the answer, at# least on the paper, is simple: m4 is the best tool to parse m4, so# let's use m4.## Therefore the specification is:## I want to be able to tell Autoconf, well, m4, that the macro I# am currently defining is an obsolete macro (so that the user is# warned), which code is the code to use when running autoconf,# but that the very same code has to be used when running# autoupdate. To summarize, the interface I want is# `AU_DEFUN(OLD-NAME, NEW-CODE)'.### Now for the technical details.## When running autoconf, except for the warning, AU_DEFUN is basically# AC_DEFUN.## When running autoupdate, we want *only* OLD-NAMEs to be expanded.# This obviously means that acgeneral.m4 and acspecific.m4 must not be# loaded. Nonetheless, because we want to use a rich set of m4# features, m4sugar.m4 is needed. Please note that the fact that# Autoconf's macros are not loaded is positive on two points:## - we do get an updated `configure.ac', not a `configure'!## - the old macros are replaced by *calls* to the new-macros, not the# body of the new macros, since their body is not defined!!!# (Whoa, that's really beautiful!).## Additionally we need to disable the quotes when reading the input for# two reasons: first because otherwise `m4' will swallow the quotes of# other macros:## NEW([1, 2], 3)# => NEW(1, 2, 3)## and second, because we want to update the macro calls which are# quoted, i.e., we want## FOO([OLD(1, 2)])# => FOO([NEW([1, 2], [3])])## If we don't disable the quotes, only the macros called at the top# level would be updated.## So, let's disable the quotes.## Well, not quite: m4sugar.m4 still needs to use quotes for some macros.# Well, in this case, when running in autoupdate code, each macro first# reestablishes the quotes, expands itself, and disables the quotes.## Thinking a bit more, you realize that in fact, people may use `define'# `ifelse' etc. in their files, and you certainly don't want to process# them. Another example is `dnl': you don't want to remove the# comments. You then realize you don't want exactly to import m4sugar:# you want to specify when it is enabled (macros active), and disabled.# m4sugar provides m4_disable/m4_enable to this end.## You're getting close to it. Now remains one task: how to handle# twofold definitions?## Remember that the same AU_DEFUN must be understood in two different# ways, the AC way, and the AU way.## One first solution is to check whether acgeneral.m4 was loaded. But# that's definitely not cute. Another is simply to install `hooks',# that is to say, to keep in some place m4 knows, late `define' to be# triggered *only* in AU mode.## You first think to design AU_DEFUN like this:## 1. AC_DEFUN(OLD-NAME,# [Warn the user OLD-NAME is obsolete.# NEW-CODE])## 2. Store for late AU binding([define(OLD_NAME,# [Reestablish the quotes.# NEW-CODE# Disable the quotes.])])## but this will not work: NEW-CODE has probably $1, $2 etc. and these# guys will be replaced with the argument of `Store for late AU binding'# when you call it.## I don't think there is a means to avoid this using this technology# (remember that $1 etc. are *always* expanded in m4). You may also try# to replace them with $[1] to preserve them for a later evaluation, but# if `Store for late AU binding' is properly written, it will remain# quoted till the end...## You have to change technology. Since the problem is that `$1'# etc. should be `consumed' right away, one solution is to define now a# second macro, `AU_OLD-NAME', and to install a hook than binds OLD-NAME# to AU_OLD-NAME. Then, autoupdate.m4 just need to run the hooks. By# the way, the same method was used in autoheader.### # Third implementation: m4 namespaces by m4sugar# # ==============================================## Actually, this implementation was just a clean up of the previous# implementation: instead of defining hooks by hand, m4sugar was equipped# with `namespaces'. What are they?## Sometimes we want to disable some *set* of macros, and restore them# later. We provide support for this via namespaces.## There are basically three characters playing this scene: defining a# macro in a namespace, disabling a namespace, and restoring a namespace# (i.e., all the definitions it holds).## Technically, to define a MACRO in NAMESPACE means to define the macro# named `NAMESPACE::MACRO' to the VALUE. At the same time, we append# `undefine(NAME)' in the macro named `m4_disable(NAMESPACE)', and# similarly a binding of NAME to the value of `NAMESPACE::MACRO' in# `m4_enable(NAMESPACE)'. These mechanisms allow to bind the macro of# NAMESPACE and to unbind them at will.## Of course this implementation is really inefficient: m4 has to grow# strings which can become quickly huge, which slows it significantly.## In particular one should avoid as much as possible to use `define' for# temporaries. Now that `define' as quite a complex meaning, it is an# expensive operations that should be limited to macros. Use# `m4_define' for temporaries.## Private copies of the macros we used in entering / exiting the m4sugar# namespace. It is much more convenient than fighting with the renamed# version of define etc.#### Those two implementations suffered from serious problems:## - namespaces were really expensive, and incurred a major performance# loss on `autoconf' itself, not only `autoupdate'. One solution# would have been the limit the use of namespaces to `autoupdate', but# that's again some complications on m4sugar, which really doesn't need# this. So we wanted to get rid of the namespaces.## - since the quotes were disabled, autoupdate was sometimes making# wrong guesses, for instance on:## foo([1, 2])## m4 saw 2 arguments: `[1'and `2]'. A simple solution, somewhat# fragile, is to reestablish the quotes right before all the obsolete# macros, i.e., to use sed so that the previous text becomes## changequote([, ])foo([1, 2])## To this end, one wants to trace the definition of obsolete macros.## It was there that the limitations of the namespace approach became# painful: because it was a complex machinery playing a lot with the# builtins of m4 (hence, quite fragile), tracing was almost impossible.### So this approach was dropped.### # The fourth implementation: two steps# # ====================================## If you drop the uses of namespaces, you no longer can compute the# updated value, and replace the old call with it simultaneously.## Obviously you will use m4 to compute the updated values, but you may# use some other tool to achieve the replacement. Personally, I trust# nobody but m4 to parse m4, so below, m4 will perform the two tasks.## How can m4 be used to replace *some* macros calls with newer values.# Well, that's dead simple: m4 should learn the definitions of obsolete# macros, forget its builtins, disable the quotes, and then run on the# input file, which amounts to doing this:## divert(-1)dnl# changequote([, ])# define([OLD], [NEW([$1, $2], m4_eval([$1 + $2]))changequote()])# undefine([dnl])# undefine([m4_eval])# # Some more undefines...# changequote()# divert(0)dnl# dnl The Unbelievable Truth# changequote([, ])OLD(1, 2)# NEW([0, 0],# 0)## which will result in## dnl The Unbelievable Truth# NEW(1, 2, m4_eval(1 + 2))# NEW([0, 0],# 0)## Grpmh. Two problems. A minor problem: it would have been much better# to have the `m4_eval' computed, and a major problem: you lost the# quotation in the result.## Let's address the big problem first. One solution is to define any# modern macro to rewrite its calls with the proper quotation, thanks to# `$@'. Again, tracing the `define's makes it possible to know which# are these macros, so you input is:## divert(-1)dnl# changequote([, ])# define([OLD], [NEW([$1, $2], m4_eval([$1 + $2]))changequote()])# define([NEW], [[NEW($@)]changequote()])# undefine([dnl])# undefine([m4_eval])# # Some more undefines...# changequote()# divert(0)dnl# dnl The Unbelievable Truth# changequote([, ])OLD(1, 2)# changequote([, ])NEW([0, 0],# 0)## which results in## dnl The Unbelievable Truth# NEW([1, 2],[m4_eval(1 + 2)])# NEW([0, 0],[0])## Our problem is solved, i.e., the first call to `NEW' is properly# quoted, but introduced another problem: we changed the layout of the# second calls, which can be a drama in the case of huge macro calls# (think of `AC_TRY_RUN' for instance). This example didn't show it,# but we also introduced parens to macros which did not have some:## AC_INIT# => AC_INIT()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -