📜 ⬆️ ⬇️

A couple of words about Header Map in Xcode

The C / Objective C / C ++ language family needs a preprocessor. The preprocessor passes the compiled source through itself, before giving the text to the input to the compiler. Perhaps the most important part of the preprocessor’s work is to replace the #include<-> directives with the contents of the specified file. Usually indicate the relative path (ex: stdio.h , sys/stat.h ). A natural question arises - how does the preprocessor find the header files?

The classic answer is this: the preprocessor sequentially enumerates the paths in INCLUDE_PATH from the first. A relative path from the include directive is allowed relative to the (sic) folder from the INCLUDE_PATH. If the file is not found, go to the next item INCLUDE_PATH. If INCLUDE_PATH is exhausted, the compiler reports an error.

But Apple, as always, makes its own adjustments. When building in Xcode, so-called additionally are used. header map . This is the index of all header files in the project. If XCode "knows" about foobar.h, then this file will be accessible simply by name ( #include<foobar.h> ), regardless of the actual placement on the file system.
')
This is a great solution - as long as it works as intended. Unfortunately, the header map mechanism is poorly documented, which does not contribute to quick resolution of problems. I will try to fill this gap.


Header map

definition
Header Map is an index file generated by Xcode. The file is named for the current target and has the extension " .hmap ". An index is a set of string pairs of key — value. The index is used to match the full path to the header file by the argument of the include directive. Index search is case insensitive. Search in the index has a higher priority than INCLUDE_PATH. This is done to speed up the build.

By default, the header map is active. To disable, you need to create a variable USE_HEADERMAP=NO in the project configuration.

And what if the project uses several header files with the same name? With the default settings, only one of these files gets into the index - which one is impossible to predict. The same problem occurs when the file name in the project matches the system header file, case insensitive (ex: Time.h ).


View Header Map


To diagnose it is useful to look at the generated header map. This is a binary file, with confused optimization of common substrings. It's good that good people wrote a program for converting to text format.

 python headermap.py build/hmap.build/Debug/primary.build/primary.hmap 

Here primary is the name of the target.

 bar.h /Users/nickz/hmap/bar.h foo.h /Users/nickz/hmap/foo.h primary/foo.h /Users/nickz/hmap/foo.h 

If with foo.h and bar.h everything is more or less clear, then primary/foo.h raises questions. As it turned out, Xcode creates such entries for header files that are members of the current target. (In order for Xcode to allow target files to be made into target files, you need to add the copy headers build phase to it.)

PRODUCT_NAME is used as a prefix, and if you change it, the old map prefix will still appear in the header map (it appears on 3.2.5, possibly fixed in new versions). It is treated by closing-opening the project.


Settings


USE_HEADERMAP = [YES] / NO
On off.

HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT = [YES] / NO
Include header files that are members of the active target in the header map. On 3.2.5 is ignored .

HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES = [YES] / NO
Include header files that are members of the active target in the header map. Files get the prefix $(PRODUCT_NAME)/ . If the setting value is YES , such records are created for any type of purpose; otherwise, only if the target type is Framework.

HEADERMAP_INCLUDES_PROJECT_HEADERS = [YES] / NO
Include in header maps all header files from project without target. On 3.2.5 is ignored .

Full list of settings .

Source: https://habr.com/ru/post/144834/


All Articles