Quick cut at an autoconf tutorial
От | Tom Lane |
---|---|
Тема | Quick cut at an autoconf tutorial |
Дата | |
Msg-id | 25253.903310508@sss.pgh.pa.us обсуждение исходный текст |
Ответ на | Re: [HACKERS] Autoconf'd test for int64 ("Thomas G. Lockhart" <lockhart@alumni.caltech.edu>) |
Список | pgsql-hackers |
"Thomas G. Lockhart" <lockhart@alumni.caltech.edu> writes: > Using autoconf for things sounds great. I've been relying on scrappy for > that stuff, and find it a mystery myself. Marc or someone, would you be > willing to write a few sentences on how to make incremental changes to > the Postgres autoconfig system? Well, there's really no substitute for reading the autoconf manual ;-) But basically the idea is that you don't want to have your code #ifdef'ing on system ID symbols except in very specific circumstances. Usually what you really want to know is "does feature X exist here?", and the right way to handle that is to have a direct test for feature X. If you take that approach your code is a lot more likely to work out-of-the-box on a new system. Not to mention the fact that some systems like HPUX and Linux come in a lot of flavors --- testing the system ID symbols isn't good enough there anyway. What autoconf does is provide a system whereby you can make exactly the tests you need during configuration, and have the results available when your code is being compiled. The results are usually expressed in the form of configuration symbols that get defined (or not) in config.h. You can also have autoconf apply system-specific edits to other places like makefiles, but config.h is most often the file to tweak. To take the particular example at hand, I had to go through the following steps: 1. Ask myself what we really wanted to know. What we wanted to know, it seemed like, was whether either "long int" or "long long int" could be used as a 64-bit integer type. So I invented some configuration symbol names that would carry this info from autoconf to the compile-time tests needed in int8.h: /* Set to 1 if type "long int" works and is 64 bits */ #undef HAVE_LONG_INT_64 /* Set to 1 if type "long long int" works and is 64 bits */ #undef HAVE_LONG_LONG_INT_64 2. I put the above lines into src/include/config.h.in, which is the master file that autoconf will edit during configuration to create the localized version src/include/config.h (.in is the usual convention for indicating an autoconf master file). Autoconf provides automatic support for changing "#undef X" into "#define X something" when appropriate, so we start with the "#undef" format. 3. Then I needed to figure out how to test these conditions. Basically what autoconf can do is to (try to) compile and run little test programs; if it succeeds then it figures that particular feature is there. So I wrote a little program that checks sizeof(long long int) (to make sure it's 8) and also tries to do some simple arithmetic to make sure the answers come out right. You can see the details in the patch, but the important point is that if long long isn't OK, the program will either fail to compile at all, or will exit with a nonzero return status (which is program failure by Unix convention). Autoconf will only believe the test succeeded if the program compiles and exits with zero status when run. 4. After I'd tested the test program to my satisfaction, I wrapped it into this autoconf code: AC_MSG_CHECKING(whether 'long long int' is 64 bits) AC_TRY_RUN([ ... test program code here ... ], [AC_MSG_RESULT(yes) AC_DEFINE(HAVE_LONG_LONG_INT_64)], AC_MSG_RESULT(no), AC_MSG_RESULT(assuming not on target machine)) AC_TRY_RUN is a macro that's basically like an if-then-else structure. If the test program (whose text is the first argument) succeeds, the second argument is executed; if the test fails, the third argument is executed; and if autoconf knows it is cross-compiling for another machine and therefore can't run a test program at all, it doesn't try but just executes the fourth argument. Usually that last alternative should be the most conservative assumption. The AC_MSG macros are just user interface aids (they generate all that junk that the configure script prints as it runs). The important aspect is the AC_DEFINE() macro --- if that gets executed, it cues Autoconf to convert "#undef HAVE_LONG_LONG_INT_64" to "#define HAVE_LONG_LONG_INT_64 1" later on when it's generating config.h from config.h.in. (I could give AC_DEFINE a second argument if I wanted to define the symbol as some particular string instead of "1".) In the other cases, AC_DEFINE is not executed so that line of config.h.in will be left unmodified. The other thing to know to read this is that square brackets are m4's quoting convention. I made another copy that was exactly the same but it works on "long int" and defines HAVE_LONG_INT_64 if it wins. 5. Then I ran autoconf to generate a configure shell script from the configure.in source code, and I was done. 6. AC_TRY_RUN is the sledgehammer of Autoconf programming --- you only need it if you need to verify some unusual detail of a system's run-time behavior. Most of the standard sorts of problems can be dealt with using simpler Autoconf macros. For example, if I had been satisfied just to test whether the declaration "long long int" would compile, I could've just done AC_TRY_COMPILE(, [ long long int x; ], [success action], [fail action]) which would compile the code but not try to run it. There are even simpler macros that handle most of the really common cases. For example, PostgreSQL's configure.in includes AC_CHECK_HEADERS(limits.h) which tries to compile a program that says "#include <limits.h>", and if it succeeds then it automatically defines HAVE_LIMITS_H. (We still have to remember to put #undef HAVE_LIMITS_H into config.h.in, however, or the AC_DEFINE would have no visible effect.) BTW this last example should cue you that there are conventions for choosing configuration symbol names in Autoconf --- a symbol that indicates that <stdlib.h> exists should be called HAVE_STDLIB_H, and not anything else; if you violate these conventions you risk confusing autoconf experts, or even breaking some other part of configuration. (A while back we had a configuration bug because HAVE_HISTORY was getting used for two different purposes: both to indicate whether <history.h> exists and whether libhistory exists to be linked with. Following the convention prevents this error, since HAVE_HISTORY_H refers to the include file and HAVE_LIBHISTORY to the library.) 7. The configure script generated by Autoconf is a self-contained shell script that will run on darn near any Unix platform. But to generate configure from configure.in, you need to have Autoconf itself installed, and you also need GNU m4 because Autoconf is really just a script in the m4 macro processing language. You can find these at any GNU archive site if you don't have 'em already. Both are painless to install. 8. There's really no substitute for reading the autoconf manual ;-). But maybe this will motivate you to go do that. regards, tom lane
В списке pgsql-hackers по дате отправления: