19

gcc provides the -I- option, for which -I directories preceding the -I- are searched for quoted includes (#include "foo.h"), and -I directories following the -I- are searched for bracketed includes (#include <foo.h>), as well as after the others for quoted includes.

-I- has another very important effect. It removes the directory of the source file that the #include is in from the default search path. Normally a quoted include always searches the directory of the source file, and searches it before any -I or other directories. -I- therefore allows you to specify exactly where to go for quoted include files in the order you want, by removing that default path that otherwise would take priority.

So it sounds like I answered my question, yes? No. When I use -I- now, I get this nastygram:

cc1: note: obsolete option -I- used, please use -iquote instead

The problem is that -iquote does not remove the current directory from the search path. It is still always searched first, no matter what I provide to -iquote.

So the question is: how do I get the same effect as -I-, without using -I-, which has been deprecated and will eventually go away?

Elaboration:

Suppose files are laid out as follows:

srcdir/
    configure
    file1.c
    file2.c
    config.h

builddir/
    Makefile
    file1.o
    file2.o
    config.h
    libpudding.a

For various reasons, we can't remove config.h from srcdir (it will impact the build process on other platforms). However, we want to include the config.h from builddir in preference to the zconf.h in srcdir.

This can be accomplished with GCC's -I- flag, but it seems otherwise impossible.

Updated question:

Ok, it seems like the GNU CC developers deprecated -I-, but did not provide an alternative way to achieve its functionality. So my updated question is: what is the most effective way to bring this to the attention of the developers so that there is a high probability that either -I- is undeprecated (which I would find most preferable, since it is a quite elegant way to handle specifying the search, much more so and much less ugly than -iquotexxx), or that some way is provided to remove the current directory from a quoted include search path?

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • 3
    A quick scan through the GCC manual leads me to believe that this is not possible, that `-I-` is the only option with that behavior. In the past, I've decided that the simplest option for my own projects is to rename or reorganize my header files rather than futz with search paths. Source: http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Directory-Options.html#Directory-Options – Dietrich Epp Jul 23 '12 at 01:59
  • This is for out-of-source-directory builds of zlib, which has been requested by users. It doesn't have anything to do with how I want to organize my stuff for myself. – Mark Adler Jul 23 '12 at 02:17
  • Hm, I've made sure my projects supported out-of-tree builds in the past, but I've never needed to use `-I-` to accomplish it. Is this the kind of change you're looking for? https://github.com/depp/zlib – Dietrich Epp Jul 23 '12 at 03:01
  • It's complicated. (The natural tendency here seems to be that if the question is hard to answer, then it must be the wrong question.) Anyway, zconf.h is built and needs to be in builddir and is included quoted by zlib.h, which is in srcdir. The source files include zlib.h quoted. So whether zlib.h is just in srcdir or copied to builddir, there is problem with either the source files including the correct zlib.h, or zlib.h including the correct zconf.h. For other reasons, I can't change the fact that the includes are quoted. – Mark Adler Jul 23 '12 at 03:47
  • Ah, I see. So the problem is that there is a `zconf.h` in `srcdir`, but the copy in `builddir` is needed. A possible workaround is to include `"zconf.h"` directly from all the C files in the library, before including `"zlib.h"`. Edit: Okay, so that only works for C files not in the root `srcdir`. – Dietrich Epp Jul 23 '12 at 04:06
  • 1
    Well, you could also symlink all of the source files into the builddir. Maybe that's just the path of least resistance. – Dietrich Epp Jul 23 '12 at 04:11

1 Answers1

4

Having worked with annoyances of zconf.h in an out-of-tree build, I would definitely go back to your point that when a question is super-tricky, it's often the wrong question. You're absolutely right. The right question is why zconf.h exists in srcdir at all, when it should be generated from zconf.h.in. A file should either be always generated or never generated for a given set of configuration settings. It should never be both provided and generated in the same build.

The best solution here is to remove zconf.h from the source tree and always generate it from zconf.h.in just as you do in the CMake build. I've never been clear why its done one way for CMake and another for Make. If the point is that you don't have autoconf, and so you're going to use a pre-built zconf.h for make, but a CMake-generated one for CMake, then just ship it as zconf.h.in (which you do), and copy it into the build tree in the Makefile.

Getting rid of the bizarre behavior of -I- was a good move. Having multiple files in your search path which are referred to with the same name is extremely confusing and ugly. If the -I search order matters, then something is not designed correctly in your project or in your build. I should never have to guess what #include "foo.h" refers to. I should definitely never be in a situation where it is easy to find yourself editing the wrong file.

I applaud your work improving the zlib build. zlib is certainly not the hardest package to build, but it is certainly not the easiest either (particularly if you need the contrib/minizip stuff, which I invariably do).

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    zconf.h needs to be in the source directory because I impose a requirement that zlib be easily built out of the box with no scripts at all. E.g. cc -c *.c; ar rc libz.a *.o, or the equivalent commands on whatever platform. Your statements about the proper way to handle generated files only works in the subset of the world that has the tools to generate those files. When one lives in that subset, it is easy to assume that that is the whole world. – Mark Adler Jul 24 '12 at 05:04
  • I do not see why -I- is bizarre. It is a compact and elegant way to split the include path between quoted and bracketed includes. You can immediately see what the actual search path is for both quoted and bracketed includes by inspection. It is much better looking, easier to read, and easier to understand than the -iquote / -I approach. And as noted, -iquote loses a fundamental capability that -I- has. – Mark Adler Jul 24 '12 at 05:07
  • By the way, the normal script-based build process (./configure && make) _does_ always make zconf.h from zconf.h.in. So I don't get your comment. – Mark Adler Jul 24 '12 at 05:13
  • 1
    I was using the CMake system which forced me to delete zconf.h out of the source tree in order to build (which is difficult under Perforce). I have since switched to make. Re: easy build with no tools, adding the step `cp zconf.h.in zconf.h` is not an excessive tool requirement to simplify the include path, and is my recommended solution to the build problem. I stand behind my belief that any include path that is order-dependent is dangerous and confusing, and since the special-feature of `-I-` is to support an order-dependent include path, it was good to deprecate it. – Rob Napier Jul 24 '12 at 13:52
  • What system are you using? make in zlib should not be used without running ./configure first. (By the way, make is a tool.) – Mark Adler Jul 24 '12 at 13:54
  • Order-dependent include paths are still supported with -I and -iquote. So those should be deprecated also? The only thing lost with -I- (other than readability) is taking the current directory out of the search path. – Mark Adler Jul 24 '12 at 13:55
  • I'm running configure and then make now. My old system was using CMakeLists.txt, which requires removing zconf.h from the src tree (which is problematic when the source tree is in Perforce). Having a .h in the same directory as the .c that is ignored is confusing and error-prone IMO (which is likely why it's deprecated). The solution IMO is to have the config system, whether "configure/make", cmake, or a user with no build tools reading README, always create zconf.h in the build directory either by writing it or copying it from zconf.h.in. Then there is only one zconf.h. – Rob Napier Jul 24 '12 at 14:56
  • 2
    Just to add a different view to this: I have a case where I want to stub a specific header file for a unit test, but I don't want to copy the original source file around. As such I do have a need to remove the path the source file is in from the include search path. Besides, include paths are always order dependent. If you have two files named identically in paths that are included you get a dependency on order. – bluebrother Jul 15 '13 at 20:29