├── .gitignore
├── README.md
├── ex_01
└── configure.ac
├── ex_02
├── Makefile
└── program.cc
├── ex_03
├── Makefile.in
├── configure.ac
└── program.cc
├── ex_04
├── Makefile.in
├── configure.ac
└── program.cc
├── ex_05
├── Makefile.in
├── configure.ac
└── program.cc
├── ex_06
├── Makefile.in
├── configure.ac
├── hello_libz.cc
├── hello_no_libz.cc
└── program.cc
├── ex_07
├── Makefile.in
├── config.h.in
├── configure.ac
└── program.cc
├── ex_08
├── Makefile.in
├── configure.ac
├── hello_libz.cc
├── hello_no_libz.cc
└── program.cc
├── ex_09
├── Makefile.in
├── configure.ac
├── hello_libz.cc
├── hello_no_libz.cc
└── program.cc
├── ex_10
└── configure.ac
├── ex_11
├── configure.ac
└── m4
│ └── ax_cxx_compile_stdcxx.m4
├── ex_12
└── configure.ac
└── ex_13
└── configure.ac
/.gitignore:
--------------------------------------------------------------------------------
1 | .*.swp
2 | Makefile
3 | autom4te.cache
4 | *.o
5 | config.log
6 | config.status
7 | configure
8 | program
9 | config.h
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # A brief introduction to Autoconf (2nd edition)
2 |
3 | ## Preface
4 |
5 | A long time ago I autoconf-ized the build system for
6 | [libCVD](http://www.edwardrosten.com/cvd/index.html).
7 | It was one of the
8 | best decisions I made with that library. It took me a while because there wasn't
9 | a good “getting started” guide, so
10 | [I wrote one](http://www.edwardrosten.com/code/autoconf/). It's been the
11 | top link for “autoconf tutorial” on google for a while.
12 |
13 | Don't go there.
14 |
15 | The trouble is I wrote it after my first Autoconf project back in 2005 or so.
16 | I've learned how to use it better since then and it's also moved on. It'll get
17 | you started, but probably teach you bad habits. I've also since come to the
18 | conclusion that while autoconf is entirely separate from make and can be used
19 | without it, it makes much more sense to have examples with makefiles because
20 | they are almost always used together.
21 |
22 |
23 | ## Introduction
24 |
25 | Autoconf is a system for generating a script which will automatically determine
26 | the presence of things which your project either depends upon, or can make use
27 | of. Once these have been determined, autoconf can export this information in
28 | various formats suitable for your project to use. Autoconf scripts themselves
29 | are written in a combination of shell and M4 (a macro processing language
30 | considerably more capable than the C preprocessor). Autoconf essentially runs
31 | the preprocessor on your script to produce a portable shell script which will
32 | perform all the requisite tests, produce handy log files, preprocess template
33 | files, for example to generate `Makefile` from `Makefile.in` and and take a standard
34 | set of command line arguments.
35 |
36 | There are several tools in the suite, including automake (for automatically
37 | generating makefiles) and autoscan (for scanning source trees to make configure
38 | scripts). I'm not going to cover them. However, while autoconf has nothing to
39 | do with Make, by far the most common use of it is to generate a Makefile. I only
40 | use GNU Make, and so the examples may well use GNU Make only features.
41 |
42 | In order to read this tutorial, a knowledge of shell scripting is assumed, but
43 | not essential for the basic examples. No knowledge of M4 is needed, but it worth
44 | knowing especially if you want to write your own custom tests which you wish to
45 | reuse.
46 |
47 | ## Hello, World.
48 |
49 | Grab the code in [example 1](ex_01), or put this in configure.ac:
50 |
51 | ```autoconf
52 | AC_INIT(myconfig, version-0.1)
53 | AC_MSG_NOTICE([Hello, world.])
54 |
55 | ```
56 | Now compile it and run it
57 | ```bash
58 | autoconf
59 | ./configure
60 | ```
61 | And you get:
62 | ```text
63 | ex_01 $./configure
64 | configure: Hello, world.
65 | ex_01 $
66 | ```
67 | Alriiight! :)
68 |
69 | Now that that's out of the way, there's a few basic things.
70 | * All public Autoconf M4 macros look like `A[CST]_??????`. There may be private versions starting with `_`, but it's generally a bad idea to use them.
71 | * M4 arguments are quoted with `[` and `]`. There is NO WAY to escape these, however, you have several options if you wish to insert `[`'s or `]`'s:
72 | 1. Use a ‘Quadrigaph’. `@<:@` gives you `[` and `@>:@` gives you `]`. Those look as nasty as they sound.
73 | 2. Balance your quotes. M4 will turn `[[]]` in to `[]`. Beware of using this in arguments to macros. Sometimes, you need to double quote as well (`[[[]]]`). This is not as nasty as it sounds, it's much, much nastier. M4 programming is quite fun in that you have such a huge of acievement when the quotes finally work correctly.
74 | 3. Change the quoting using: `changequote(<<,>>)` to change the quoting to `<<` and `>>`. The autoconf documentation (rightly, in my opinion) warns against the (over) use of this, since it can lead to unexpected results. This is also as nasty... see the pattern here?
75 | 4. Avoid `[` and `]` whereever possible.
76 | As a result, you can't easily use the shell command `[` to perform tests. You have to use test instead.
77 | * If you make bad shell code, the errors probably won't appear until you run the configure script.
78 | * Configure scripts are almost always called configure.ac
79 | * Bear in mind that this is a tutorial. Many macros provide optional arguments which allow you to change the way of doing things. There may be many more ways of solving a problem than I've covered here.
80 |
81 | ## A basic project
82 |
83 | Since the purpose of autoconf is compiling projects, it makes most sense to
84 | start with [a simple project](ex_02). The project as it stands just has a
85 | Makefile. Go in to [ex_02](ex_02) and do:
86 | ```bash
87 | make
88 | ./program
89 | ```
90 | If all goes well and you have a C++ compiler installed, then you should get:
91 | ```text
92 | Hello, I am a program
93 | ```
94 | [It's now going to be autoconfized](ex_03). First, we rename `Makefile` to
95 | `Makefile.in` and edit it look like this:
96 | ```make
97 | CXX=@CXX@
98 | LD=@CXX@
99 | CXXFLAGS=@CXXFLAGS@
100 |
101 | program: program.o
102 | $(LD) -o $@ $^
103 |
104 | .PHONY: clean
105 | clean:
106 | rm -f program *.o
107 |
108 | ```
109 | It's more or less the same, but instead of hard-wiring the compiler names and
110 | flags and so on, we put in placeholders that the configure script will
111 | substitute. All the placeholders are of the form @foo@. I've also added
112 | a "make clean" rule.
113 |
114 | We now need a matching configure script:
115 | ```autoconf
116 | AC_INIT(program, 1.0)
117 |
118 | dnl Switch to a C++ compiler, and check if it works.
119 | AC_LANG(C++)
120 | AC_PROG_CXX
121 |
122 | dnl Process Makefile.in to create Makefile
123 | AC_OUTPUT(Makefile)
124 | ```
125 | By the way, dnl in autoconf is a comment. That's because of M4 and M4
126 | is... best not to go there right now.
127 |
128 | Now, compile the configure script by typing "autoconf" and you're ready to
129 | perform the standard build incantation:
130 | ```bash
131 | ./configure && make
132 | ```
133 | I get the output:
134 | ```text
135 | checking for g++... g++
136 | checking whether the C++ compiler works... yes
137 | checking for C++ compiler default output file name... a.out
138 | checking for suffix of executables...
139 | checking whether we are cross compiling... no
140 | checking for suffix of object files... o
141 | checking whether we are using the GNU C++ compiler... yes
142 | checking whether g++ accepts -g... yes
143 | configure: creating ./config.status
144 | config.status: creating Makefile
145 | g++ -g -O2 -c -o program.o program.cc
146 | g++ -o program program.o
147 |
148 | ```
149 | That's basically it. You now have a fully armed and operational configure
150 | script. Because autoconf is a decent system, it already comes with all the
151 | different features. You can, for example change the compiler flags:
152 | ```text
153 | make clean
154 | ./configure CXXFLAGS="-Wall -Wextra" && make
155 | ```
156 | or, you can change the compiler if you like:
157 | ```bash
158 | make clean
159 | ./configure CXX=g++-5 && make
160 |
161 | ```
162 | Naturally that will fail if you don't have that compiler. You can even cross
163 | compile! First, install the AVR toolchain (on ubuntu sudo apt-get install gcc-avr binutils-avr avr-libc) if you can, then run:
164 | ```bash
165 | ./configure --host avr && make
166 | ```
167 | You should get the output:
168 | ```text
169 | checking for avr-g++... avr-g++
170 | checking whether the C++ compiler works... yes
171 | checking for C++ compiler default output file name... a.out
172 | checking for suffix of executables...
173 | checking whether we are cross compiling... yes
174 | checking for suffix of object files... o
175 | checking whether we are using the GNU C++ compiler... yes
176 | checking whether avr-g++ accepts -g... yes
177 | configure: creating ./config.status
178 | config.status: creating Makefile
179 | avr-g++ -g -O2 -c -o program.o program.cc
180 | program.cc:1:20: fatal error: iostream: No such file or directory
181 | #include
182 | ^
183 | compilation terminated.
184 | make: *** [program.o] Error 1
185 | ```
186 | Wait, what?
187 |
188 | The AVR is a “non hosted” platform in that it has no OS. That means that you
189 | can't expect obvious bits of the C++ standard library to be there. While this is
190 | an obscure case, it does illustrate the next topic very nicely which is:
191 |
192 | ## Performing basic tests
193 |
194 | So first we need some tests to perform. The iostream example is a little
195 | contrived, so I'll bring in a really common library, [zlib](http://zlib.com).
196 | The new program [example 5](ex_05) now outputs its data gzip compressed.
197 |
198 | First, we need to modify the [Makefile.in](ex_05/Makefile.in) to use the library
199 | flags. First, we add the template substitutions:
200 | ```Make
201 | LDFLAGS=@LDFLAGS@
202 | LIBS=@LIBS@
203 | ```
204 | then we change the build line to use them:
205 | ```Make
206 | program: program.o
207 | $(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
208 | ```
209 | At this point you might wonder, “Why not save typing and just use `@LIBS@`
210 | everywhere?”. It's a good question. The answer is that you can, but if you ever
211 | end up debugging things and you want to make a quick, temporary change by
212 | editing the generated Makefile, you will curse yourself because instead of changing things in
213 | one place, you have to change it everywhere.
214 |
215 | So, now, put the following lines in the `configure.ac` file:
216 | ```autoconf
217 | AC_CHECK_HEADERS(zlib.h)
218 | AC_SEARCH_LIBS(deflate, z)
219 | ```
220 | The first function compiles a minimal program against each of the specified
221 | headers (you can give more than one), and the second checks for the function
222 | "deflate" in any one of the listed libraries.
223 | If you were to run the configure script, you'd get something like this in the
224 | output:
225 | ```text
226 | checking zlib.h usability... yes
227 | checking zlib.h presence... yes
228 | checking for zlib.h... yes
229 | checking for library containing deflate... -lz
230 | ```
231 | That's pretty good, and you can now build the program, however, if the test
232 | fails then the configure script will continue and give you a makefile which
233 | would fail to build your program.
234 |
235 | So now what?
236 |
237 | At this point you need to do something with the results of the test. What you
238 | want to do, and how you want to do it depend strongly on what you're trying to
239 | achieve. The simplest case is a hard dependency, where failure to find the
240 | library prevents the configure script from completing.
241 |
242 | Both the functions above set various variables on success, in this case:
243 | ```shell
244 | ac_cv_header_zlib_h=yes
245 | ac_cv_search_deflate=-lz
246 | ```
247 | You can look in config.log, that has a list of everything which is defined. You
248 | can perform tests with shell logic on those if you like. However, those
249 | functions also provide two optional arguments: action on success and action on
250 | failure.
251 |
252 | Probably the easiest solution is to do this:
253 |
254 | ```autoconf
255 | AC_CHECK_HEADERS(zlib.h, [], [AC_ERROR([A working zlib is required])])
256 | AC_SEARCH_LIBS(deflate, z, [], [AC_ERROR([A working zlib is required])])
257 | ```
258 | Now try misspelling “deflate” and rerunning autoconf and configure. You'll see
259 | it fail like this:
260 | ```text
261 | checking zlib.h usability... yes
262 | checking zlib.h presence... yes
263 | checking for zlib.h... yes
264 | checking for library containing deflte... no
265 | configure: error: A working zlib is required
266 | ```
267 |
268 | ## What's going on under the hood?
269 |
270 | I find many tools and systems easier to understand if I know what's going on
271 | under the hood. I think it makes predicting the behaviour and debugging
272 | substantially easier. Fortunately, autoconf is fairly straightforward in that
273 | regard.
274 |
275 | Autoconf is essentially a compiler that compiles the `configure.ac` script into
276 | a shell script which can then run on any platform without autoconf being
277 | present. Well, I say compiler... It's actually all in a language called M4. M4
278 | is a macro processing system, like the C preprocessor on steroids (and PCP).
279 | When you run autoconf, it defines a whole bunch of M4 macros and then runs your
280 | script through the M4 preprocessor. The macros all get expanded (they all
281 | contain shell code) and out comes pure shell code with no trace of the M4 or
282 | autoconf languages left behind.
283 |
284 | The macros are in all caps, and everything else is passed through as-is with no
285 | modification. That's why you can write logic in shell code too: it just ends up
286 | in the configure script.
287 |
288 | Most of the tests in autoconf are to do with compiled code. To do these,
289 | autoconf emits small programs to a file, then runs that file through the
290 | compiler and possibly linker, and checks the resulting error codes. For example:
291 |
292 | ```M4
293 | AC_CHECK_LIB(m, cos)
294 | ```
295 | Will generate a program looking something like this:
296 | ```C
297 | char cos ();
298 | int main ()
299 | {
300 | cos ();
301 | return 0;
302 | }
303 | ```
304 | Then attempt to compile and link it with libm. Autoconf does similar things for
305 | `AC_CHECK_HEADERS`, but only runs the compiler, not the linker too. If you want
306 | to see more details, then create a test which you know will fail, run the script
307 | and and look in `config.log`. It only stores the program fragments from tests
308 | that fail.
309 |
310 |
311 | ## More advanced test results
312 |
313 | Sometimes, dependencies are optional. There are of course an infinite number of
314 | ways of dealing with those. The two common ones are via conditional compilation
315 | (i.e. setting macros) or via choosing between different source files. I strongly
316 | prefer the latter if possible.
317 |
318 | Now, the tests so far will set things which can be used (like the presence or
319 | absence of `-lz` in the library flags), but they are independent. You want to
320 | enable the dependency if and only if all relavent tests pass. I find the easiest
321 | way of doing that is using a construct like this:
322 |
323 | ```autoconf
324 | a=0
325 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
326 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
327 |
328 | if test $a == 0
329 | then
330 | dnl Thing to do if the library is present
331 | ;
332 | else
333 | dnl Thing to do if the library is not present
334 | ;
335 | fi
336 |
337 | ```
338 |
339 | I'm now going to make zlib an optional dependency.
340 |
341 | ### Compiling alternate files
342 |
343 | The first thing to do is to [provide two alternatives](ex_06), one for zlib and
344 | one without. Obviously in this case the example is a little contrived but we
345 | want to compile [hello_libz.cc](ex_06/hello_libz.cc) if we find zlib and
346 | [hello_no_libz.cc](ex_06/hello_no_libz.cc) if we don't. Either way, `main()` is
347 | the same, and just calls the `hello()` function.
348 |
349 | Now, alter [Makefile.in](ex_06/Makefile.in) so it can use another parameter that
350 | we get from `configure`:
351 | ```make
352 | objs=@objs@
353 |
354 | program: program.o $(objs)
355 | $(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
356 | ```
357 | And alter [configure.ac](ex_06/configure.ac) so it populates @objs@ with either
358 | one object file or another.
359 | ```autoconf
360 | dnl List of object files as determined by autoconf
361 | object_files=""
362 |
363 | a=0
364 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
365 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
366 |
367 | if test $a == 0
368 | then
369 | object_files="$object_files hello_libz.o"
370 | else
371 | object_files="$object_files hello_no_libz.o"
372 | fi
373 |
374 | dnl Make AC_OUTPUT substitute the contents of $object_files for @objs@
375 | AC_SUBST(objs, ["$object_files"])
376 | ```
377 |
378 | Now `configure` will choose between one of the two source files to compile and
379 | link, depending on the result of the test. The complete program will work either
380 | way.
381 |
382 | ### Conditional compilation
383 |
384 | The [other main way](ex_07) of having autoconf affect the build is via conditional
385 | compilation. You could export `-D` definitions to the CXXFLAGS or a custom
386 | variable. That's a bad idea because your program will have a dependency on the
387 | arguments, and make doesn't track or examine those dependencies. The standard
388 | way is to generate a `config.h` file instead. The process is similar to, but not
389 | identical to creating a makefile. The relevant part of
390 | [configure.ac](ex_07/configure.ac) is:
391 | ```autoconf
392 | a=0
393 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
394 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
395 |
396 | if test $a == 0
397 | then
398 | AC_DEFINE(HAVE_LIBZ)
399 | fi
400 |
401 | AC_CONFIG_HEADERS(config.h)
402 | ```
403 | `AC_DEFINE` will cause a #define to be written in `config.h`. **IMPORTANT:**
404 | `AC_CONFIG_HEADERS` must come before `AC_OUTPUT` otherwise it willbe silently
405 | ignored. [config.h.in](ex_07/config.h.in) is a template of an include file, but
406 | substitutions are done on `#undef` lines, it must contain:
407 | ```C
408 | #undef HAVE_LIBZ
409 | ```
410 | If `HAVE_LIBZ` is exported by `configure`, then that line is commented out. The
411 | [C++ code](ex_07/program.c) can then `#include ` and use the macros.
412 |
413 | #### :neckbeard: Ed's Soapbox :neckbeard:
414 |
415 | Avoid `config.h` as much as possible. Disadvantages are:
416 |
417 | 1. Every file depending on `config.h` must be rebuilt if `config.h` changes even
418 | if the change is irrelevant.
419 | 2. Conditional compilation is ugly and can lead to tangled messes of dead code.
420 | 3. It's generally good practice to avoid the preprocessor where possible.
421 | 4. If you're building a library and you've got a `config.h` included from the
422 | public headers, then everything using the library has to be rebuilt if
423 | `config.h` changes.
424 | 5. More source files means better parallel builds.
425 |
426 | This isn't a rigid rule. Sometimes the clearest, simplest and most elegant
427 | solution to some gnarly cross-platform portability problem involves the
428 | preprocessor. In most cases though however, the cleanest portable designs will
429 | rely on separating off platform specific parts into different modules and files.
430 |
431 | Regarding point 4, you should really avoid having a public config.h if at all
432 | possible. When you can't keep the dependencies on it as small as possible, by putting
433 | anything not required to be public in a private config.h. Autoconf allows you to
434 | specify a whole list of headers.
435 |
436 | ### Nicer dependencies with --with and --enable
437 |
438 | So if you've made it this far, you probably noticed that debugging and checking
439 | the scripts was a bit of a pain, because you had to edit them to make one of the
440 | tests fail then rerun autoconf, then put it back again. Autoconf provides two
441 | methods of configuration. They are almost identical in function, but the
442 | conventions are:
443 | * `--enable-foo` enable feature foo. This is typically used to enable or disable
444 | an entire feature, such as `--enable-gui`.
445 | * `--with-bar` use dependency bar. This is typically used to switch on/off a
446 | dependency. That may have an effect on a whole feature. For example
447 | `--without-gtk` might end up disabling the GUI if no other toolkit is
448 | available.
449 |
450 | If a script understands `--with-bar`, it will also understand `--without-bar`
451 | which is exactly equivalent to `--with-bar=no`. That means you can also supply
452 | arguments to `with`. `--enable-foo` works in the same way. Both styles simply
453 | set an environment variable. You can then act on that with the usual shell
454 | scripting.
455 |
456 | The format is:
457 | ```autoconf
458 | AC_ARG_WITH(zlib, [AS_HELP_STRING([--without-zlib], [do not use zlib])])
459 | ```
460 | The first argument is the feature, and it will set `$with_zlib` to the value
461 | specified (blank if the argument is not used). The second argument is the text
462 | which appears if `./configure --help` is run. `AS_HELP_STRING` simply makes
463 | everything line up and look pretty. Much like the other tests, you can also
464 | specify actions for if the commandline argument is present or absent.
465 |
466 |
467 | [This example](ex_08) is very similar to [Example 6](ex_06), except that the
468 | relevant part of [configure.ac](ex_08/configure.ac) is now:
469 | ```configure
470 | AC_ARG_WITH(zlib, [AS_HELP_STRING([--without-zlib], [do not use zlib])])
471 |
472 | zlib_objs=hello_no_libz.o
473 | if test "$with_zlib" != no
474 | then
475 | a=0
476 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
477 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
478 |
479 | if test $a == 0
480 | then
481 | zlib_objs=hello_libz.o
482 | fi
483 | fi
484 |
485 | object_files="$object_files $zlib_objs"
486 |
487 | ```
488 | Now, if `--without-zlib` is specified then it doesn't even try to run the tests,
489 | and carries on as if the tests have failed.
490 |
491 | ## Out of tree builds
492 |
493 | Out of tree builds are one of those features that are rarely used, but probably
494 | ought to be used more. They're kind of handy because with the same source tree,
495 | you can build various versions (standard, debugging, cross compiled) from a
496 | single source tree, without having to keep multiple copies in sync. It's also so
497 | easy to do that you may as well do it.
498 |
499 | Autoconf supports it by providing @srcdir@ which tells you the directory of the
500 | configure script and of course by extension the source code. That's it as far as
501 | autoconf goes, it's completely automatic.
502 |
503 | You then need to use the virtual path (vpath) feature of make. Essentially, add
504 | the line
505 | ```make
506 | VPATH=@srcdir@
507 | ```
508 | to Makefile.in, and now make will more or less overlay VPATH on the current
509 | directory when it comes to file lookups.
510 |
511 | That's all there is to is. Go into [example 9](ex_09) and run autoconf to create
512 | the configure script. Now go into /tmp and type something like:
513 | ```shell
514 | /path/to/autoconf_tutorial/ex_09/configure && make && ./program | zcat
515 | ```
516 | It should work just as well as if you ran configure and make from within the
517 | source directory.
518 |
519 | ## Moving on
520 |
521 | At this point you now have a basic, but fully featured autoconf build system.
522 | Most of what to do can probably be accomplished with what you've covered so far,
523 | however you may come across things which aren't covered.
524 |
525 | If you do get into writing your own tests, then it's a very good idea to build
526 | off the autoconf macros if at all possible. I know from experience that it's an
527 | especially bad idea to write tests that probe the machine you're running the
528 | autoconf script from because then you won't be able to deploy the resulting
529 | program on a different mahchine (for example if you're cross compiling).
530 |
531 | Even without machine specific tests, there are other things you might want to
532 | look for or other parts of the build system you might want to probe.
533 |
534 | ### Debugging
535 |
536 | There are several levels of debugging which you need to do. There's debugging
537 | your shell code (I'm not going to help there), debugging tests in the configure
538 | script and debugging the generated files.
539 |
540 | If you're debugging autoconf tests, the best place to look is `config.log`. That
541 | stores lots of useful information about tests that fail, including the compiler
542 | line with all flags and the bit of code being compiled. It's often quite large,
543 | so you'll have to search through it. You can also put your own text in the log
544 | to aid that process.
545 |
546 | Here's [an example](ex_10):
547 |
548 | ```autoconf
549 | AC_INIT(myconfig, version-0.1)
550 | AC_PROG_CXX
551 |
552 |
553 | AC_SEARCH_LIBS(cos, m)
554 |
555 | echo "This library check will fail" >&AS_MESSAGE_LOG_FD
556 | AC_SEARCH_LIBS(foo, bar)
557 |
558 | AC_MSG_NOTICE([This message will appear in the log and on the screen])
559 | AC_CHECK_HEADERS(foo, bar)
560 | ```
561 | Run the script and look in the log file.
562 |
563 | Assuming your configure script runs correctly, the next layer of the stack with
564 | bugs is the generated Makefile and `config.h` if either exist. It would be
565 | awfully tedious if you had to re-run configure every time you changed one of
566 | those. Fortunately you don't.
567 |
568 | Before autoconf completes, it generates a script called `config.status`, then
569 | executes it. This script stores the results of autoconf and does the template
570 | substitutions on the .in files. So, if you edit your `Makefile.in` and run
571 | `config.status`, it'll re-generate the Makefile.
572 |
573 |
574 | ### Using other languages
575 |
576 | Autoconf supports several languages. The easiest way to switch is:
577 | ```autoconf
578 | AC_LANG(Fortran)
579 | ```
580 | which changes the language that tests are run in. There's also a stack of
581 | languages so you can push and pop them to make temporary changes.
582 |
583 |
584 | ### Other tests
585 |
586 | At this point I'm just going to list a selection of what's available. The usage
587 | should be reasonably obvious from the names. Quite a few of the marcros have
588 | `IF_ELSE` in the name, which means they just give you places to insert code for
589 | success or failure. For quite a lot of common cases, there are more specialised
590 | macros to help. Note again, this is a small selection to give a flavour. Since
591 | this is a tutorial I can't cover them all, so it's best to browse
592 | [the manual](https://www.gnu.org/software/autoconf/manual/autoconf.html) at this
593 | point.
594 | * `AC_COMPILE_IFELSE` --- useful for testing C++ header only libraries
595 | * `AC_PREPROCESS_IFELSE`
596 | * `AC_LINK_IFELSE`
597 | * `AC_RUN_IFELSE` --- this one is tricky. If you're cross compiling, you
598 | probably can't run a program you've just compiled, so you need to provide
599 | the script with some way of making a decision in that case.
600 | * `AC_PROG_AWK` --- find a working AWK. Versions exist for many of the common
601 | tools.
602 | * `AC_CHECK_TYPES([long long])`, `AC_TYPE_UINT8_T` --- check for various
603 | typedefs
604 | * `AC_OPENMP`
605 | * Anything starting `AC_MSG` for generting output that's consistent with the
606 | built in tests.
607 |
608 |
609 | ## Help! I can't test for C++14 (or something else)
610 |
611 | ### Other people's macros
612 |
613 | Autoconf provides good underlying tools, but doesn't provide tests for
614 | everything. In many cases, instead of writing your own you can instead grab one
615 | already written from [the huge official archive of
616 | macros](http://www.gnu.org/software/autoconf-archive/index.html). They're also
617 | very easy to use precisely because M4 is a macro language.
618 |
619 | Here's [an example](ex_11) for C++14. First get [this extension
620 | macro](http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html)
621 | and put it in the `m4` subdirectory. Then use it in the following way:
622 | ```M4
623 | AC_INIT(myconfig, version-0.1)
624 | AC_LANG(C++)
625 | AC_PROG_CXX
626 |
627 |
628 | m4_include([m4/ax_cxx_compile_stdcxx.m4])
629 | AX_CXX_COMPILE_STDCXX(14)
630 | ```
631 | Now your script will test for C++ 14 and fail if it isn't found. The official
632 | extension macros are generally very well tested and so it's better to use those
633 | than roll your own.
634 |
635 | ### Writing your own tests
636 |
637 | Sooner or later, you'll probably find that there's not a test for something you
638 | want to do repeatedly. For example, I like to routinely add flags to do with
639 | warnings, GDB symbols and so on. [Here's](ex_12) an example of a custom test
640 | and its use
641 | ```autoconf
642 | dnl TEST_AND_SET_CXXFLAG(flag, [program])
643 | dnl
644 | dnl This attempts to compile a program with a certain compiler flag.
645 | dnl If no program is given, then the minimal C++ program is compiled, and
646 | dnl this tests just the validity of the compiler flag.
647 | dnl
648 | define([TEST_AND_SET_CXXFLAG],[
649 | AC_MSG_CHECKING([if compiler flag $1 works])
650 |
651 | dnl Store the current CXXFLAGS
652 | save_CXXFLAGS="$CXXFLAGS"
653 |
654 | dnl Append the flag of interest
655 | CXXFLAGS="$CXXFLAGS $1"
656 |
657 | dnl Create an M4 macro, "prog", which expands to a C++ program.
658 | dnl This should either be a default one or the one specified.
659 | dnl Note that macros are not local, but there is a stack so push
660 | dnl the definition on to the stack to prevent clobbering a definition
661 | dnl that might already exist.
662 | m4_if([$2],[],[pushdef(prog, [int main(){}])], [pushdef(prog, [$2])])
663 |
664 | flag_test=0
665 |
666 | dnl See if the compiler runs
667 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([prog])], [flag_test=1],[flag_test=0])
668 |
669 | dnl De-clobber the "prog" macro
670 | popdef([prog])
671 |
672 | if test $flag_test = 1
673 | then
674 | AC_MSG_RESULT(yes)
675 | else
676 | AC_MSG_RESULT(no)
677 | dnl The flag doesn't work, so restore the old CXXFLAGS
678 | CXXFLAGS="$save_CXXFLAGS"
679 | fi
680 | ])
681 |
682 | dnl Add flags, but only if the flags weren't overridden already
683 | if test "$CXXFLAGS" == "-g -O2"
684 | then
685 |
686 | TEST_AND_SET_CXXFLAG(-Wall)
687 | TEST_AND_SET_CXXFLAG(-Wextra)
688 | TEST_AND_SET_CXXFLAG(-W)
689 | TEST_AND_SET_CXXFLAG(-O3)
690 | TEST_AND_SET_CXXFLAG(-ggdb)
691 | TEST_AND_SET_CXXFLAG(-fnot-a-valid-flag)
692 | fi
693 | ```
694 | If you run the configure script it will attempt to add a whole bunch of flags to
695 | the compiler, but it won't cause errors if any of those flags are invalid.
696 |
697 |
698 | ## Making the world a better place
699 |
700 | Who doesn't want to make the world a better place?
701 |
702 | Have you ever had the following process:
703 |
704 | 1. `./confiugure && make && make install`
705 | 2. Try running the program to discover some feature you want is missing.
706 | 3. Re configure.
707 | 4. Examine output of autoconf until your eyes bleed.
708 | 5. Finally discover the most likely things which have failed.
709 | 6. Install packages, configure and make.
710 | 7. Discover you were wrong, and repeat 4-6 until you finally get the package
711 | working
712 | 8. Then repeat 1-8 until you finally have every feature you care about, or
713 | until you simply lose the will to carry on.
714 | 9. Use your new prorgam in a desultory manner.
715 |
716 | The good news is there's no need to inflict that on your users. [In this
717 | example](ex_13), there's a configure script for a hypothetical library which
718 | handles images and video. All dependencies are optional---if it's missing
719 | libjpeg, it'll work but just not be able to handle that format for example.
720 |
721 | Here's what I do to make my scripts look nice. Firstly, I make pretty section
722 | headers in the configure output using a macro like this:
723 | ```autoconf
724 | define(SECTION_TITLE,
725 | [
726 | echo >& AS_MESSAGE_FD
727 | echo ' $1 ' | sed -e's/./-/g' >&AS_MESSAGE_FD
728 | echo ' $1' >& AS_MESSAGE_FD
729 | echo ' $1 ' | sed -e's/./-/g' >&AS_MESSAGE_FD
730 | ])
731 |
732 |
733 | SECTION_TITLE([Checking for image libraries])
734 | ```
735 | Then, I keep track of what possible options there are. First, define a list of
736 | all possible options:
737 | ```autoconf
738 | all_options="jpeg png tiff funkyimage v4l2 ffmpeg awesomevideo"
739 | ```
740 | then have another list which is the options which have been found. Whenever, you
741 | find something, then append it to the list:
742 | ```autoconf
743 | options=
744 | ...
745 | options="$options jpeg"
746 |
747 | ```
748 | So, a complete test would look like this:
749 | ```autoconf
750 | a=0
751 | AC_CHECK_HEADERS(png.h, [], [a=1])
752 | AC_SEARCH_LIBS(png_create_info_struct, png, [], [a=1])
753 | if test $a == 0
754 | then
755 | options="$options png"
756 | fi
757 |
758 | ```
759 | Then at the end of the script, print out both a list of options and list of the
760 | missing options. I do that with a little bit of shell scripting:
761 | ```shell
762 | echo "$options" "$all_options" | tr ' ' '\n' | sort | uniq -u | tr '\n' ' '
763 | ```
764 | The [resulting configure script](ex_13/configure.ac) gives an output which I
765 | think is much easier to read and to figure out the results of than the usual
766 | wall of text:
767 | ```text
768 | $ ./configure
769 | checking for g++... g++
770 | checking whether the C++ compiler works... yes
771 | checking for C++ compiler default output file name... a.out
772 | checking for suffix of executables...
773 | checking whether we are cross compiling... no
774 | checking for suffix of object files... o
775 | checking whether we are using the GNU C++ compiler... yes
776 | checking whether g++ accepts -g... yes
777 | checking how to run the C++ preprocessor... g++ -E
778 | checking for grep that handles long lines and -e... /bin/grep
779 | checking for egrep... /bin/grep -E
780 | checking for ANSI C header files... yes
781 | checking for sys/types.h... yes
782 | checking for sys/stat.h... yes
783 | checking for stdlib.h... yes
784 | checking for string.h... yes
785 | checking for memory.h... yes
786 | checking for strings.h... yes
787 | checking for inttypes.h... yes
788 | checking for stdint.h... yes
789 | checking for unistd.h... yes
790 | checking iostream usability... yes
791 | checking iostream presence... yes
792 | checking for iostream... yes
793 |
794 | ----------------------------------
795 | Checking for image libraries
796 | ----------------------------------
797 | checking jpeglib.h usability... yes
798 | checking jpeglib.h presence... yes
799 | checking for jpeglib.h... yes
800 | checking for library containing jpeg_set_defaults... -ljpeg
801 | checking png.h usability... yes
802 | checking png.h presence... yes
803 | checking for png.h... yes
804 | checking for library containing png_create_info_struct... -lpng
805 | checking tiffio.h usability... yes
806 | checking tiffio.h presence... yes
807 | checking for tiffio.h... yes
808 | checking for library containing TIFFOpen... -ltiff
809 | checking funkyimage.h usability... no
810 | checking funkyimage.h presence... no
811 | checking for funkyimage.h... no
812 | checking for library containing funkyopen... no
813 |
814 | --------------------------------
815 | Checking for video options
816 | --------------------------------
817 | checking linux/videodev2.h usability... yes
818 | checking linux/videodev2.h presence... yes
819 | checking for linux/videodev2.h... yes
820 | checking for ffmpeg...
821 | checking libavcodec/avcodec.h usability... yes
822 | checking libavcodec/avcodec.h presence... yes
823 | checking for libavcodec/avcodec.h... yes
824 | checking libavformat/avformat.h usability... yes
825 | checking libavformat/avformat.h presence... yes
826 | checking for libavformat/avformat.h... yes
827 | checking libswscale/swscale.h usability... yes
828 | checking libswscale/swscale.h presence... yes
829 | checking for libswscale/swscale.h... yes
830 | checking for library containing main... none required
831 | checking for library containing av_read_frame... -lavformat
832 | checking for library containing avcodec_open2... -lavcodec
833 | checking for library containing sws_getContext... -lswscale
834 | checking awesomevid.h usability... no
835 | checking awesomevid.h presence... no
836 | checking for awesomevid.h... no
837 | checking for library containing openawesome... no
838 |
839 | ---------------------------
840 | Configuration results
841 | ---------------------------
842 | Options:
843 | jpeg png tiff v4l2 ffmpeg
844 |
845 | Missing options:
846 | awesomevideo funkyimage
847 |
848 |
849 | CXXFLAGS=-g -O2
850 | LDFLAGS=
851 | LIBS=-lswscale -lavcodec -lavformat -ltiff -lpng -ljpeg
852 | $ █
853 | ```
854 |
855 |
856 |
857 |
858 | ## What about automake and libtool?
859 |
860 | Er... yes they exist.
861 |
862 | I'm not going to cover them because I don't use them for a variety of reasons.
863 | Back when I learned autoconf, automake always generated recursive Makefiles.
864 | [Those are bad](aegis.sourceforge.net/auug97.pdf) for many reasons but
865 | especially if you do parallel builds with `make -J 4`. I had a dual processor
866 | machine back when multiple processors or cores were rare so it mattered to me
867 | more than most people. I also like GNU Make particularly, and I'm entirely happy
868 | with writing Makefiles to the point where I don't feel the need for extra
869 | automation.
870 |
871 | Libtool was (for me) a relatively frequent and hard to debug source of build
872 | errors in other people's packages. In fairness, this may well have been due to
873 | misuse of libtool, but either way I never learned it. Libtool was especially
874 | important back in the olden days when systems were very diverse, and when static
875 | libraries were measureably more efficient than dynamic ones. These days I tend
876 | to compile my .a files with PIC (so I can blob them into a .so plugin easily),
877 | and platforms with significant differences seem to have reduced to Linux/\*BSD,
878 | OSX and Cygwin and MinGW though in the latter cases it will also work the same
879 | way as Linux. So, in short I've not felt I'd gain all that much by learning it.
880 |
881 |
882 |
883 |
884 |
885 |
886 |
887 |
888 |
889 |
--------------------------------------------------------------------------------
/ex_01/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(myconfig, version-0.1)
2 | AC_MSG_NOTICE([Hello, world.])
3 |
--------------------------------------------------------------------------------
/ex_02/Makefile:
--------------------------------------------------------------------------------
1 | CXX=g++
2 | LD=g++
3 | CXXFLAGS=-Wall -Wextra
4 |
5 |
6 | program: program.o
7 | $(LD) -o $@ $^
8 |
--------------------------------------------------------------------------------
/ex_02/program.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | using namespace std;
4 |
5 | int main()
6 | {
7 | cout << "Hello, I am a program\n";
8 | }
9 |
--------------------------------------------------------------------------------
/ex_03/Makefile.in:
--------------------------------------------------------------------------------
1 | CXX=@CXX@
2 | LD=@CXX@
3 | CXXFLAGS=@CXXFLAGS@
4 |
5 | program: program.o
6 | $(LD) -o $@ $^
7 |
8 | .PHONY: clean
9 | clean:
10 | rm -f program *.o
11 |
12 |
--------------------------------------------------------------------------------
/ex_03/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(program, 1.0)
2 |
3 | dnl Switch to a C++ compiler, and check if it works.
4 | AC_LANG(C++)
5 | AC_PROG_CXX
6 |
7 | dnl Process Makefile.in to create Makefile
8 | AC_OUTPUT(Makefile)
9 |
10 |
--------------------------------------------------------------------------------
/ex_03/program.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | using namespace std;
4 |
5 | int main()
6 | {
7 | cout << "Hello, I am a program\n";
8 | }
9 |
--------------------------------------------------------------------------------
/ex_04/Makefile.in:
--------------------------------------------------------------------------------
1 | CXX=@CXX@
2 | LD=@CXX@
3 | CXXFLAGS=@CXXFLAGS@
4 |
5 | program: program.o
6 | $(LD) -o $@ $^
7 |
8 | .PHONY: clean
9 | clean:
10 | rm -f program *.o
11 |
12 |
--------------------------------------------------------------------------------
/ex_04/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(program, 1.0)
2 |
3 | dnl Switch to a C++ compiler, and check if it works.
4 | AC_LANG(C++)
5 | AC_PROG_CXX
6 |
7 | AC_CHECK_HEADERS(iostream)
8 |
9 | dnl Process Makefile.in to create Makefile
10 | AC_OUTPUT(Makefile)
11 |
12 |
--------------------------------------------------------------------------------
/ex_04/program.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | using namespace std;
4 |
5 | int main()
6 | {
7 | cout << "Hello, I am a program\n";
8 | }
9 |
--------------------------------------------------------------------------------
/ex_05/Makefile.in:
--------------------------------------------------------------------------------
1 | CXX=@CXX@
2 | LD=@CXX@
3 | CXXFLAGS=@CXXFLAGS@
4 | LDFLAGS=@LDFLAGS@
5 | LIBS=@LIBS@
6 |
7 | program: program.o
8 | $(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
9 |
10 | .PHONY: clean
11 | clean:
12 | rm -f program *.o
13 |
14 |
--------------------------------------------------------------------------------
/ex_05/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(program, 1.0)
2 |
3 | dnl Switch to a C++ compiler, and check if it works.
4 | AC_LANG(C++)
5 | AC_PROG_CXX
6 |
7 | AC_CHECK_HEADERS(zlib.h, [], [AC_ERROR([A working zlib is required])])
8 | AC_SEARCH_LIBS(deflate, z, [], [AC_ERROR([A working zlib is required])])
9 |
10 | dnl Process Makefile.in to create Makefile
11 | AC_OUTPUT(Makefile)
12 |
13 |
--------------------------------------------------------------------------------
/ex_05/program.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | using namespace std;
5 |
6 | int main()
7 | {
8 | //Output a string, compressed in gzip format.
9 | unsigned char in[] = "Hello, I am a program\n";
10 | unsigned char out[1024] = {};
11 |
12 | z_stream strm = {};
13 | deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 8+16, 9, Z_DEFAULT_STRATEGY);
14 | strm.next_in = in;
15 | strm.avail_in = sizeof(in);
16 | strm.next_out = out;
17 | strm.avail_out = sizeof(out);
18 | deflate(&strm, Z_FINISH);
19 | deflateEnd(&strm);
20 |
21 | cout.write((const char*)out, strm.total_out);
22 | }
23 |
--------------------------------------------------------------------------------
/ex_06/Makefile.in:
--------------------------------------------------------------------------------
1 | CXX=@CXX@
2 | LD=@CXX@
3 | CXXFLAGS=@CXXFLAGS@
4 | LDFLAGS=@LDFLAGS@
5 | LIBS=@LIBS@
6 |
7 | objs=@objs@
8 |
9 | program: program.o $(objs)
10 | $(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
11 |
12 | .PHONY: clean
13 | clean:
14 | rm -f program *.o
15 |
16 |
--------------------------------------------------------------------------------
/ex_06/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(program, 1.0)
2 |
3 | dnl Switch to a C++ compiler, and check if it works.
4 | AC_LANG(C++)
5 | AC_PROG_CXX
6 |
7 | dnl List of object files as determined by autoconf
8 | object_files=""
9 |
10 | a=0
11 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
12 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
13 |
14 | if test $a == 0
15 | then
16 | object_files="$object_files hello_libz.o"
17 | else
18 | object_files="$object_files hello_no_libz.o"
19 | fi
20 |
21 | dnl Make AC_OUTPUT substitute the contents of $object_files for @objs@
22 | AC_SUBST(objs, ["$object_files"])
23 |
24 | dnl Process Makefile.in to create Makefile
25 | AC_OUTPUT(Makefile)
26 |
27 |
--------------------------------------------------------------------------------
/ex_06/hello_libz.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | using namespace std;
5 |
6 | void hello()
7 | {
8 | //Output a string, compressed in gzip format.
9 | unsigned char in[] = "Hello, I am a program\n";
10 | unsigned char out[1024] = {};
11 |
12 | z_stream strm = {};
13 | deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 8+16, 9, Z_DEFAULT_STRATEGY);
14 | strm.next_in = in;
15 | strm.avail_in = sizeof(in);
16 | strm.next_out = out;
17 | strm.avail_out = sizeof(out);
18 | deflate(&strm, Z_FINISH);
19 | deflateEnd(&strm);
20 |
21 | cout.write((const char*)out, strm.total_out);
22 | }
23 |
--------------------------------------------------------------------------------
/ex_06/hello_no_libz.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | using namespace std;
4 |
5 | void hello()
6 | {
7 | char data[]={0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
8 | 0x03,0xf3,0x48,0xcd,0xc9,0xc9,0xd7,0x51,0xf0,
9 | 0x54,0x48,0xcc,0x55,0x48,0x54,0x28,0x28,0xca,
10 | 0x4f,0x2f,0x4a,0xcc,0xe5,0x62,0x00,0x00,0x45,
11 | 0x29,0xde,0xb8,0x17,0x00,0x00,0x00};
12 |
13 | cout.write(data, sizeof(data));
14 | }
15 |
--------------------------------------------------------------------------------
/ex_06/program.cc:
--------------------------------------------------------------------------------
1 | using namespace std;
2 |
3 | //The purpose here is to teach autoconf, not C++ best
4 | //practices...
5 | void hello();
6 |
7 | int main()
8 | {
9 | hello();
10 | }
11 |
--------------------------------------------------------------------------------
/ex_07/Makefile.in:
--------------------------------------------------------------------------------
1 | CXX=@CXX@
2 | LD=@CXX@
3 | CXXFLAGS=@CXXFLAGS@
4 | LDFLAGS=@LDFLAGS@
5 | LIBS=@LIBS@
6 |
7 | program: program.o
8 | $(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
9 |
10 | .PHONY: clean
11 | clean:
12 | rm -f program *.o
13 |
14 |
--------------------------------------------------------------------------------
/ex_07/config.h.in:
--------------------------------------------------------------------------------
1 | #ifndef INCLUDE_CONFIG_H_df90858
2 | #define INCLUDE_CONFIG_H_df90858
3 |
4 | #undef HAVE_ZLIB
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/ex_07/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(program, 1.0)
2 |
3 | dnl Switch to a C++ compiler, and check if it works.
4 | AC_LANG(C++)
5 | AC_PROG_CXX
6 |
7 |
8 | a=0
9 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
10 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
11 |
12 | if test $a == 0
13 | then
14 | AC_DEFINE(HAVE_LIBZ)
15 | fi
16 |
17 |
18 | AC_CONFIG_HEADERS(config.h)
19 | AC_OUTPUT(Makefile)
20 |
21 |
--------------------------------------------------------------------------------
/ex_07/program.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include "config.h"
3 | using namespace std;
4 |
5 |
6 | #ifdef HAVE_ZLIB
7 | #include
8 | void hello()
9 | {
10 | //Output a string, compressed in gzip format.
11 | unsigned char in[] = "Hello, I am a program\n";
12 | unsigned char out[1024] = {};
13 |
14 | z_stream strm = {};
15 | deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 8+16, 9, Z_DEFAULT_STRATEGY);
16 | strm.next_in = in;
17 | strm.avail_in = sizeof(in);
18 | strm.next_out = out;
19 | strm.avail_out = sizeof(out);
20 | deflate(&strm, Z_FINISH);
21 | deflateEnd(&strm);
22 |
23 | cout.write((const char*)out, strm.total_out);
24 | }
25 | #else
26 | void hello()
27 | {
28 | char data[]={0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
29 | 0x03,0xf3,0x48,0xcd,0xc9,0xc9,0xd7,0x51,0xf0,
30 | 0x54,0x48,0xcc,0x55,0x48,0x54,0x28,0x28,0xca,
31 | 0x4f,0x2f,0x4a,0xcc,0xe5,0x62,0x00,0x00,0x45,
32 | 0x29,0xde,0xb8,0x17,0x00,0x00,0x00};
33 |
34 | cout.write(data, sizeof(data));
35 | }
36 | #endif
37 |
38 | int main()
39 | {
40 | hello();
41 | }
42 |
--------------------------------------------------------------------------------
/ex_08/Makefile.in:
--------------------------------------------------------------------------------
1 | CXX=@CXX@
2 | LD=@CXX@
3 | CXXFLAGS=@CXXFLAGS@
4 | LDFLAGS=@LDFLAGS@
5 | LIBS=@LIBS@
6 |
7 | objs=@objs@
8 |
9 | program: program.o $(objs)
10 | $(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
11 |
12 | .PHONY: clean
13 | clean:
14 | rm -f program *.o
15 |
16 |
--------------------------------------------------------------------------------
/ex_08/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(program, 1.0)
2 |
3 | dnl Switch to a C++ compiler, and check if it works.
4 | AC_LANG(C++)
5 | AC_PROG_CXX
6 |
7 | dnl List of object files as determined by autoconf
8 | object_files=""
9 |
10 |
11 | AC_ARG_WITH(zlib, [AS_HELP_STRING([--without-zlib], [do not use zlib])])
12 |
13 | zlib_objs=hello_no_libz.o
14 | if test "$with_zlib" != no
15 | then
16 | a=0
17 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
18 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
19 |
20 | if test $a == 0
21 | then
22 | zlib_objs=hello_libz.o
23 | fi
24 | fi
25 |
26 | object_files="$object_files $zlib_objs"
27 |
28 |
29 |
30 | dnl Make AC_OUTPUT substitute the contents of $object_files for @objs@
31 | AC_SUBST(objs, ["$object_files"])
32 |
33 | dnl Process Makefile.in to create Makefile
34 | AC_OUTPUT(Makefile)
35 |
36 |
--------------------------------------------------------------------------------
/ex_08/hello_libz.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | using namespace std;
5 |
6 | void hello()
7 | {
8 | //Output a string, compressed in gzip format.
9 | unsigned char in[] = "Hello, I am a program\n";
10 | unsigned char out[1024] = {};
11 |
12 | z_stream strm = {};
13 | deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 8+16, 9, Z_DEFAULT_STRATEGY);
14 | strm.next_in = in;
15 | strm.avail_in = sizeof(in);
16 | strm.next_out = out;
17 | strm.avail_out = sizeof(out);
18 | deflate(&strm, Z_FINISH);
19 | deflateEnd(&strm);
20 |
21 | cout.write((const char*)out, strm.total_out);
22 | }
23 |
--------------------------------------------------------------------------------
/ex_08/hello_no_libz.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | using namespace std;
4 |
5 | void hello()
6 | {
7 | char data[]={0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
8 | 0x03,0xf3,0x48,0xcd,0xc9,0xc9,0xd7,0x51,0xf0,
9 | 0x54,0x48,0xcc,0x55,0x48,0x54,0x28,0x28,0xca,
10 | 0x4f,0x2f,0x4a,0xcc,0xe5,0x62,0x00,0x00,0x45,
11 | 0x29,0xde,0xb8,0x17,0x00,0x00,0x00};
12 |
13 | cout.write(data, sizeof(data));
14 | }
15 |
--------------------------------------------------------------------------------
/ex_08/program.cc:
--------------------------------------------------------------------------------
1 | using namespace std;
2 |
3 | //The purpose here is to teach autoconf, not C++ best
4 | //practices...
5 | void hello();
6 |
7 | int main()
8 | {
9 | hello();
10 | }
11 |
--------------------------------------------------------------------------------
/ex_09/Makefile.in:
--------------------------------------------------------------------------------
1 | CXX=@CXX@
2 | LD=@CXX@
3 | CXXFLAGS=@CXXFLAGS@
4 | LDFLAGS=@LDFLAGS@
5 | LIBS=@LIBS@
6 | VPATH=@srcdir@
7 | objs=@objs@
8 |
9 | program: program.o $(objs)
10 | $(LD) -o $@ $^ $(LDFLAGS) $(LIBS)
11 |
12 | .PHONY: clean
13 | clean:
14 | rm -f program *.o
15 |
16 |
--------------------------------------------------------------------------------
/ex_09/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(program, 1.0)
2 |
3 | dnl Switch to a C++ compiler, and check if it works.
4 | AC_LANG(C++)
5 | AC_PROG_CXX
6 |
7 | dnl List of object files as determined by autoconf
8 | object_files=""
9 |
10 |
11 | AC_ARG_WITH(zlib, [AS_HELP_STRING([--without-zlib], [do not use zlib])])
12 |
13 | zlib_objs=hello_no_libz.o
14 | if test "$with_zlib" != no
15 | then
16 | a=0
17 | AC_CHECK_HEADERS(zlib.h, [], [a=1])
18 | AC_SEARCH_LIBS(deflate, z, [], [a=1])
19 |
20 | if test $a == 0
21 | then
22 | zlib_objs=hello_libz.o
23 | fi
24 | fi
25 |
26 | object_files="$object_files $zlib_objs"
27 |
28 |
29 |
30 | dnl Make AC_OUTPUT substitute the contents of $object_files for @objs@
31 | AC_SUBST(objs, ["$object_files"])
32 |
33 | dnl Process Makefile.in to create Makefile
34 | AC_OUTPUT(Makefile)
35 |
36 |
--------------------------------------------------------------------------------
/ex_09/hello_libz.cc:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | using namespace std;
5 |
6 | void hello()
7 | {
8 | //Output a string, compressed in gzip format.
9 | unsigned char in[] = "Hello, I am a program\n";
10 | unsigned char out[1024] = {};
11 |
12 | z_stream strm = {};
13 | deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 8+16, 9, Z_DEFAULT_STRATEGY);
14 | strm.next_in = in;
15 | strm.avail_in = sizeof(in);
16 | strm.next_out = out;
17 | strm.avail_out = sizeof(out);
18 | deflate(&strm, Z_FINISH);
19 | deflateEnd(&strm);
20 |
21 | cout.write((const char*)out, strm.total_out);
22 | }
23 |
--------------------------------------------------------------------------------
/ex_09/hello_no_libz.cc:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | using namespace std;
4 |
5 | void hello()
6 | {
7 | char data[]={0x1f,0x8b,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
8 | 0x03,0xf3,0x48,0xcd,0xc9,0xc9,0xd7,0x51,0xf0,
9 | 0x54,0x48,0xcc,0x55,0x48,0x54,0x28,0x28,0xca,
10 | 0x4f,0x2f,0x4a,0xcc,0xe5,0x62,0x00,0x00,0x45,
11 | 0x29,0xde,0xb8,0x17,0x00,0x00,0x00};
12 |
13 | cout.write(data, sizeof(data));
14 | }
15 |
--------------------------------------------------------------------------------
/ex_09/program.cc:
--------------------------------------------------------------------------------
1 | using namespace std;
2 |
3 | //The purpose here is to teach autoconf, not C++ best
4 | //practices...
5 | void hello();
6 |
7 | int main()
8 | {
9 | hello();
10 | }
11 |
--------------------------------------------------------------------------------
/ex_10/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(myconfig, version-0.1)
2 | AC_PROG_CXX
3 |
4 |
5 | AC_SEARCH_LIBS(cos, m)
6 |
7 | echo "This library check will fail" >&AS_MESSAGE_LOG_FD
8 | AC_SEARCH_LIBS(foo, bar)
9 |
10 | AC_MSG_NOTICE([This message will appear in the log and on the screen])
11 | AC_CHECK_HEADERS(foo, bar)
12 |
--------------------------------------------------------------------------------
/ex_11/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(myconfig, version-0.1)
2 | AC_LANG(C++)
3 | AC_PROG_CXX
4 |
5 |
6 | m4_include([m4/ax_cxx_compile_stdcxx.m4])
7 | AX_CXX_COMPILE_STDCXX(14)
8 |
9 |
--------------------------------------------------------------------------------
/ex_11/m4/ax_cxx_compile_stdcxx.m4:
--------------------------------------------------------------------------------
1 | # ===========================================================================
2 | # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
3 | # ===========================================================================
4 | #
5 | # SYNOPSIS
6 | #
7 | # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
8 | #
9 | # DESCRIPTION
10 | #
11 | # Check for baseline language coverage in the compiler for the specified
12 | # version of the C++ standard. If necessary, add switches to CXX and
13 | # CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
14 | # or '14' (for the C++14 standard).
15 | #
16 | # The second argument, if specified, indicates whether you insist on an
17 | # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
18 | # -std=c++11). If neither is specified, you get whatever works, with
19 | # preference for an extended mode.
20 | #
21 | # The third argument, if specified 'mandatory' or if left unspecified,
22 | # indicates that baseline support for the specified C++ standard is
23 | # required and that the macro should error out if no mode with that
24 | # support is found. If specified 'optional', then configuration proceeds
25 | # regardless, after defining HAVE_CXX${VERSION} if and only if a
26 | # supporting mode is found.
27 | #
28 | # LICENSE
29 | #
30 | # Copyright (c) 2008 Benjamin Kosnik
31 | # Copyright (c) 2012 Zack Weinberg
32 | # Copyright (c) 2013 Roy Stogner
33 | # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov
34 | # Copyright (c) 2015 Paul Norman
35 | # Copyright (c) 2015 Moritz Klammler
36 | #
37 | # Copying and distribution of this file, with or without modification, are
38 | # permitted in any medium without royalty provided the copyright notice
39 | # and this notice are preserved. This file is offered as-is, without any
40 | # warranty.
41 |
42 | #serial 4
43 |
44 | dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
45 | dnl (serial version number 13).
46 |
47 | AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
48 | m4_if([$1], [11], [],
49 | [$1], [14], [],
50 | [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
51 | [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
52 | m4_if([$2], [], [],
53 | [$2], [ext], [],
54 | [$2], [noext], [],
55 | [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
56 | m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
57 | [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
58 | [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
59 | [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
60 | AC_LANG_PUSH([C++])dnl
61 | ac_success=no
62 | AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
63 | ax_cv_cxx_compile_cxx$1,
64 | [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
65 | [ax_cv_cxx_compile_cxx$1=yes],
66 | [ax_cv_cxx_compile_cxx$1=no])])
67 | if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
68 | ac_success=yes
69 | fi
70 |
71 | m4_if([$2], [noext], [], [dnl
72 | if test x$ac_success = xno; then
73 | for switch in -std=gnu++$1 -std=gnu++0x; do
74 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
75 | AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
76 | $cachevar,
77 | [ac_save_CXX="$CXX"
78 | CXX="$CXX $switch"
79 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
80 | [eval $cachevar=yes],
81 | [eval $cachevar=no])
82 | CXX="$ac_save_CXX"])
83 | if eval test x\$$cachevar = xyes; then
84 | CXX="$CXX $switch"
85 | if test -n "$CXXCPP" ; then
86 | CXXCPP="$CXXCPP $switch"
87 | fi
88 | ac_success=yes
89 | break
90 | fi
91 | done
92 | fi])
93 |
94 | m4_if([$2], [ext], [], [dnl
95 | if test x$ac_success = xno; then
96 | dnl HP's aCC needs +std=c++11 according to:
97 | dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
98 | dnl Cray's crayCC needs "-h std=c++11"
99 | for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
100 | cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
101 | AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
102 | $cachevar,
103 | [ac_save_CXX="$CXX"
104 | CXX="$CXX $switch"
105 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
106 | [eval $cachevar=yes],
107 | [eval $cachevar=no])
108 | CXX="$ac_save_CXX"])
109 | if eval test x\$$cachevar = xyes; then
110 | CXX="$CXX $switch"
111 | if test -n "$CXXCPP" ; then
112 | CXXCPP="$CXXCPP $switch"
113 | fi
114 | ac_success=yes
115 | break
116 | fi
117 | done
118 | fi])
119 | AC_LANG_POP([C++])
120 | if test x$ax_cxx_compile_cxx$1_required = xtrue; then
121 | if test x$ac_success = xno; then
122 | AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
123 | fi
124 | fi
125 | if test x$ac_success = xno; then
126 | HAVE_CXX$1=0
127 | AC_MSG_NOTICE([No compiler with C++$1 support was found])
128 | else
129 | HAVE_CXX$1=1
130 | AC_DEFINE(HAVE_CXX$1,1,
131 | [define if the compiler supports basic C++$1 syntax])
132 | fi
133 | AC_SUBST(HAVE_CXX$1)
134 | ])
135 |
136 |
137 | dnl Test body for checking C++11 support
138 |
139 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
140 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
141 | )
142 |
143 |
144 | dnl Test body for checking C++14 support
145 |
146 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
147 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
148 | _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
149 | )
150 |
151 |
152 | dnl Tests for new features in C++11
153 |
154 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
155 |
156 | // If the compiler admits that it is not ready for C++11, why torture it?
157 | // Hopefully, this will speed up the test.
158 |
159 | #ifndef __cplusplus
160 |
161 | #error "This is not a C++ compiler"
162 |
163 | #elif __cplusplus < 201103L
164 |
165 | #error "This is not a C++11 compiler"
166 |
167 | #else
168 |
169 | namespace cxx11
170 | {
171 |
172 | namespace test_static_assert
173 | {
174 |
175 | template
176 | struct check
177 | {
178 | static_assert(sizeof(int) <= sizeof(T), "not big enough");
179 | };
180 |
181 | }
182 |
183 | namespace test_final_override
184 | {
185 |
186 | struct Base
187 | {
188 | virtual void f() {}
189 | };
190 |
191 | struct Derived : public Base
192 | {
193 | virtual void f() override {}
194 | };
195 |
196 | }
197 |
198 | namespace test_double_right_angle_brackets
199 | {
200 |
201 | template < typename T >
202 | struct check {};
203 |
204 | typedef check single_type;
205 | typedef check> double_type;
206 | typedef check>> triple_type;
207 | typedef check>>> quadruple_type;
208 |
209 | }
210 |
211 | namespace test_decltype
212 | {
213 |
214 | int
215 | f()
216 | {
217 | int a = 1;
218 | decltype(a) b = 2;
219 | return a + b;
220 | }
221 |
222 | }
223 |
224 | namespace test_type_deduction
225 | {
226 |
227 | template < typename T1, typename T2 >
228 | struct is_same
229 | {
230 | static const bool value = false;
231 | };
232 |
233 | template < typename T >
234 | struct is_same
235 | {
236 | static const bool value = true;
237 | };
238 |
239 | template < typename T1, typename T2 >
240 | auto
241 | add(T1 a1, T2 a2) -> decltype(a1 + a2)
242 | {
243 | return a1 + a2;
244 | }
245 |
246 | int
247 | test(const int c, volatile int v)
248 | {
249 | static_assert(is_same::value == true, "");
250 | static_assert(is_same::value == false, "");
251 | static_assert(is_same::value == false, "");
252 | auto ac = c;
253 | auto av = v;
254 | auto sumi = ac + av + 'x';
255 | auto sumf = ac + av + 1.0;
256 | static_assert(is_same::value == true, "");
257 | static_assert(is_same::value == true, "");
258 | static_assert(is_same::value == true, "");
259 | static_assert(is_same::value == false, "");
260 | static_assert(is_same::value == true, "");
261 | return (sumf > 0.0) ? sumi : add(c, v);
262 | }
263 |
264 | }
265 |
266 | namespace test_noexcept
267 | {
268 |
269 | int f() { return 0; }
270 | int g() noexcept { return 0; }
271 |
272 | static_assert(noexcept(f()) == false, "");
273 | static_assert(noexcept(g()) == true, "");
274 |
275 | }
276 |
277 | namespace test_constexpr
278 | {
279 |
280 | template < typename CharT >
281 | unsigned long constexpr
282 | strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
283 | {
284 | return *s ? strlen_c_r(s + 1, acc + 1) : acc;
285 | }
286 |
287 | template < typename CharT >
288 | unsigned long constexpr
289 | strlen_c(const CharT *const s) noexcept
290 | {
291 | return strlen_c_r(s, 0UL);
292 | }
293 |
294 | static_assert(strlen_c("") == 0UL, "");
295 | static_assert(strlen_c("1") == 1UL, "");
296 | static_assert(strlen_c("example") == 7UL, "");
297 | static_assert(strlen_c("another\0example") == 7UL, "");
298 |
299 | }
300 |
301 | namespace test_rvalue_references
302 | {
303 |
304 | template < int N >
305 | struct answer
306 | {
307 | static constexpr int value = N;
308 | };
309 |
310 | answer<1> f(int&) { return answer<1>(); }
311 | answer<2> f(const int&) { return answer<2>(); }
312 | answer<3> f(int&&) { return answer<3>(); }
313 |
314 | void
315 | test()
316 | {
317 | int i = 0;
318 | const int c = 0;
319 | static_assert(decltype(f(i))::value == 1, "");
320 | static_assert(decltype(f(c))::value == 2, "");
321 | static_assert(decltype(f(0))::value == 3, "");
322 | }
323 |
324 | }
325 |
326 | namespace test_uniform_initialization
327 | {
328 |
329 | struct test
330 | {
331 | static const int zero {};
332 | static const int one {1};
333 | };
334 |
335 | static_assert(test::zero == 0, "");
336 | static_assert(test::one == 1, "");
337 |
338 | }
339 |
340 | namespace test_lambdas
341 | {
342 |
343 | void
344 | test1()
345 | {
346 | auto lambda1 = [](){};
347 | auto lambda2 = lambda1;
348 | lambda1();
349 | lambda2();
350 | }
351 |
352 | int
353 | test2()
354 | {
355 | auto a = [](int i, int j){ return i + j; }(1, 2);
356 | auto b = []() -> int { return '0'; }();
357 | auto c = [=](){ return a + b; }();
358 | auto d = [&](){ return c; }();
359 | auto e = [a, &b](int x) mutable {
360 | const auto identity = [](int y){ return y; };
361 | for (auto i = 0; i < a; ++i)
362 | a += b--;
363 | return x + identity(a + b);
364 | }(0);
365 | return a + b + c + d + e;
366 | }
367 |
368 | int
369 | test3()
370 | {
371 | const auto nullary = [](){ return 0; };
372 | const auto unary = [](int x){ return x; };
373 | using nullary_t = decltype(nullary);
374 | using unary_t = decltype(unary);
375 | const auto higher1st = [](nullary_t f){ return f(); };
376 | const auto higher2nd = [unary](nullary_t f1){
377 | return [unary, f1](unary_t f2){ return f2(unary(f1())); };
378 | };
379 | return higher1st(nullary) + higher2nd(nullary)(unary);
380 | }
381 |
382 | }
383 |
384 | namespace test_variadic_templates
385 | {
386 |
387 | template
388 | struct sum;
389 |
390 | template
391 | struct sum
392 | {
393 | static constexpr auto value = N0 + sum::value;
394 | };
395 |
396 | template <>
397 | struct sum<>
398 | {
399 | static constexpr auto value = 0;
400 | };
401 |
402 | static_assert(sum<>::value == 0, "");
403 | static_assert(sum<1>::value == 1, "");
404 | static_assert(sum<23>::value == 23, "");
405 | static_assert(sum<1, 2>::value == 3, "");
406 | static_assert(sum<5, 5, 11>::value == 21, "");
407 | static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
408 |
409 | }
410 |
411 | // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
412 | // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
413 | // because of this.
414 | namespace test_template_alias_sfinae
415 | {
416 |
417 | struct foo {};
418 |
419 | template
420 | using member = typename T::member_type;
421 |
422 | template
423 | void func(...) {}
424 |
425 | template
426 | void func(member*) {}
427 |
428 | void test();
429 |
430 | void test() { func(0); }
431 |
432 | }
433 |
434 | } // namespace cxx11
435 |
436 | #endif // __cplusplus >= 201103L
437 |
438 | ]])
439 |
440 |
441 | dnl Tests for new features in C++14
442 |
443 | m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
444 |
445 | // If the compiler admits that it is not ready for C++14, why torture it?
446 | // Hopefully, this will speed up the test.
447 |
448 | #ifndef __cplusplus
449 |
450 | #error "This is not a C++ compiler"
451 |
452 | #elif __cplusplus < 201402L
453 |
454 | #error "This is not a C++14 compiler"
455 |
456 | #else
457 |
458 | namespace cxx14
459 | {
460 |
461 | namespace test_polymorphic_lambdas
462 | {
463 |
464 | int
465 | test()
466 | {
467 | const auto lambda = [](auto&&... args){
468 | const auto istiny = [](auto x){
469 | return (sizeof(x) == 1UL) ? 1 : 0;
470 | };
471 | const int aretiny[] = { istiny(args)... };
472 | return aretiny[0];
473 | };
474 | return lambda(1, 1L, 1.0f, '1');
475 | }
476 |
477 | }
478 |
479 | namespace test_binary_literals
480 | {
481 |
482 | constexpr auto ivii = 0b0000000000101010;
483 | static_assert(ivii == 42, "wrong value");
484 |
485 | }
486 |
487 | namespace test_generalized_constexpr
488 | {
489 |
490 | template < typename CharT >
491 | constexpr unsigned long
492 | strlen_c(const CharT *const s) noexcept
493 | {
494 | auto length = 0UL;
495 | for (auto p = s; *p; ++p)
496 | ++length;
497 | return length;
498 | }
499 |
500 | static_assert(strlen_c("") == 0UL, "");
501 | static_assert(strlen_c("x") == 1UL, "");
502 | static_assert(strlen_c("test") == 4UL, "");
503 | static_assert(strlen_c("another\0test") == 7UL, "");
504 |
505 | }
506 |
507 | namespace test_lambda_init_capture
508 | {
509 |
510 | int
511 | test()
512 | {
513 | auto x = 0;
514 | const auto lambda1 = [a = x](int b){ return a + b; };
515 | const auto lambda2 = [a = lambda1(x)](){ return a; };
516 | return lambda2();
517 | }
518 |
519 | }
520 |
521 | namespace test_digit_seperators
522 | {
523 |
524 | constexpr auto ten_million = 100'000'000;
525 | static_assert(ten_million == 100000000, "");
526 |
527 | }
528 |
529 | namespace test_return_type_deduction
530 | {
531 |
532 | auto f(int& x) { return x; }
533 | decltype(auto) g(int& x) { return x; }
534 |
535 | template < typename T1, typename T2 >
536 | struct is_same
537 | {
538 | static constexpr auto value = false;
539 | };
540 |
541 | template < typename T >
542 | struct is_same
543 | {
544 | static constexpr auto value = true;
545 | };
546 |
547 | int
548 | test()
549 | {
550 | auto x = 0;
551 | static_assert(is_same::value, "");
552 | static_assert(is_same::value, "");
553 | return x;
554 | }
555 |
556 | }
557 |
558 | } // namespace cxx14
559 |
560 | #endif // __cplusplus >= 201402L
561 |
562 | ]])
563 |
--------------------------------------------------------------------------------
/ex_12/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(myconfig, version-0.1)
2 | AC_LANG(C++)
3 | AC_PROG_CXX
4 |
5 |
6 | dnl TEST_AND_SET_CXXFLAG(flag, [program])
7 | dnl
8 | dnl This attempts to compile a program with a certain compiler flag.
9 | dnl If no program is given, then the minimal C++ program is compiled, and
10 | dnl this tests just the validity of the compiler flag.
11 | dnl
12 | define([TEST_AND_SET_CXXFLAG],[
13 | AC_MSG_CHECKING([if compiler flag $1 works])
14 |
15 | dnl Store the current CXXFLAGS
16 | save_CXXFLAGS="$CXXFLAGS"
17 |
18 | dnl Append the flag of interest
19 | CXXFLAGS="$CXXFLAGS $1"
20 |
21 | dnl Create an M4 macro, "prog", which expands to a C++ program.
22 | dnl This should either be a default one or the one specified.
23 | dnl Note that macros are not local, but there is a stack so push
24 | dnl the definition on to the stack to prevent clobbering a definition
25 | dnl that might already exist.
26 | m4_if([$2],[],[pushdef(prog, [int main(){}])], [pushdef(prog, [$2])])
27 |
28 | flag_test=0
29 |
30 | dnl See if the compiler runs
31 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([prog])], [flag_test=1],[flag_test=0])
32 |
33 | dnl De-clobber the "prog" macro
34 | popdef([prog])
35 |
36 | if test $flag_test = 1
37 | then
38 | AC_MSG_RESULT(yes)
39 | else
40 | AC_MSG_RESULT(no)
41 | dnl The flag doesn't work, so restore the old CXXFLAGS
42 | CXXFLAGS="$save_CXXFLAGS"
43 | fi
44 | ])
45 |
46 |
47 | dnl Add flags, but only if the flags weren't overridden already
48 | if test "$CXXFLAGS" == "-g -O2"
49 | then
50 |
51 | TEST_AND_SET_CXXFLAG(-Wall)
52 | TEST_AND_SET_CXXFLAG(-Wextra)
53 | TEST_AND_SET_CXXFLAG(-W)
54 | TEST_AND_SET_CXXFLAG(-O3)
55 | TEST_AND_SET_CXXFLAG(-ggdb)
56 | TEST_AND_SET_CXXFLAG(-fnot-a-valid-flag)
57 | fi
58 |
59 |
--------------------------------------------------------------------------------
/ex_13/configure.ac:
--------------------------------------------------------------------------------
1 | AC_INIT(myconfig, version-0.1)
2 | AC_LANG(C++)
3 | AC_PROG_CXX
4 |
5 | dnl list of all possible optional components
6 | all_options="jpeg png tiff funkyimage v4l2 ffmpeg awesomevideo"
7 |
8 | dnl When a component is found, append it here
9 | options=
10 |
11 | dnl Force the compiler to run once and do all the basic checks
12 | dnl if you don't, it will do the test on the first invocation
13 | dnl below and so your pretty section titles won't work as well
14 | AC_CHECK_HEADERS(iostream)
15 |
16 | dnl Small macro to print out a nice, pretty section title.
17 | define(SECTION_TITLE,
18 | [
19 | echo >& AS_MESSAGE_FD
20 | echo ' $1 ' | sed -e's/./-/g' >&AS_MESSAGE_FD
21 | echo ' $1' >& AS_MESSAGE_FD
22 | echo ' $1 ' | sed -e's/./-/g' >&AS_MESSAGE_FD
23 | ])
24 |
25 |
26 | SECTION_TITLE([Checking for image libraries])
27 |
28 | a=0
29 | AC_CHECK_HEADERS(jpeglib.h, [], [a=1])
30 | AC_SEARCH_LIBS(jpeg_set_defaults, jpeg, [], [a=1])
31 | if test $a == 0
32 | then
33 | options="$options jpeg"
34 | fi
35 |
36 | a=0
37 | AC_CHECK_HEADERS(png.h, [], [a=1])
38 | AC_SEARCH_LIBS(png_create_info_struct, png, [], [a=1])
39 | if test $a == 0
40 | then
41 | options="$options png"
42 | fi
43 |
44 | a=0
45 | AC_CHECK_HEADERS(tiffio.h, [], [a=1])
46 | AC_SEARCH_LIBS(TIFFOpen, tiff, [], [a=1])
47 | if test $a == 0
48 | then
49 | options="$options tiff"
50 | fi
51 |
52 | a=0
53 | AC_CHECK_HEADERS(funkyimage.h, [], [a=1])
54 | AC_SEARCH_LIBS(funkyopen, funkyimage, [], [a=1])
55 | if test $a == 0
56 | then
57 | options="$options tiff"
58 | fi
59 |
60 |
61 | SECTION_TITLE([Checking for video options])
62 |
63 | a=0
64 | AC_CHECK_HEADERS(linux/videodev2.h, [], [a=1])
65 | if test $a == 0
66 | then
67 | options="$options v4l2"
68 | fi
69 |
70 |
71 |
72 | dnl this one is quite big, so give some helpful extra
73 | dnl messages
74 | AC_MSG_CHECKING([for ffmpeg])
75 | AC_MSG_RESULT([])
76 |
77 | a=0
78 | AC_CHECK_HEADERS([libavcodec/avcodec.h libavformat/avformat.h libswscale/swscale.h], [], [a=1])
79 | AC_SEARCH_LIBS(main, avutil, [], [a=1])
80 | AC_SEARCH_LIBS(av_read_frame, avformat, [], [a=1])
81 | AC_SEARCH_LIBS(avcodec_open2, avcodec, [], [a=1])
82 | AC_SEARCH_LIBS(sws_getContext, swscale, [], [a=1])
83 | if test $a == 0
84 | then
85 | options="$options ffmpeg"
86 | else
87 | AC_MSG_NOTICE([ffmpeg not found])
88 | fi
89 |
90 | a=0
91 | AC_CHECK_HEADERS(awesomevid.h, [], [a=1])
92 | AC_SEARCH_LIBS(openawesome, awesomevid, [], [a=1])
93 | if test $a == 0
94 | then
95 | options="$options awesomevideo"
96 | fi
97 |
98 |
99 |
100 |
101 | dnl Now process the options strings. Essentially, we want two lists
102 | dnl one for the options present (which we have) and one for the options
103 | dnl missing (which we don't)
104 |
105 | SECTION_TITLE([Configuration results])
106 |
107 | echo "Options:" >& AS_MESSAGE_FD
108 | echo "$options" >& AS_MESSAGE_FD
109 | echo >& AS_MESSAGE_FD
110 |
111 | echo "Missing options:" >& AS_MESSAGE_FD
112 | echo "$options" "$all_options" | tr ' ' '\n' | sort | uniq -u | tr '\n' ' ' >& AS_MESSAGE_FD
113 |
114 |
115 | echo -e "\n\n" >& AS_MESSAGE_FD
116 | echo "CXXFLAGS=$CXXFLAGS" >& AS_MESSAGE_FD
117 | echo "LDFLAGS=$LDFLAGS" >& AS_MESSAGE_FD
118 | echo "LIBS=$LIBS" >& AS_MESSAGE_FD
119 |
--------------------------------------------------------------------------------