skip to content

Clang: Cannot Use ‘Precompiled-header’ Output With Multiple -arch Options

I took me a while to figure out what was going on:

clang: cannot use 'precompiled-header' output with multiple -arch options

For once, Stack Overflow was of little help.

Here is an excerpt of the GNU Makefile I’m using to compile my project:

define build
CC-$(platform)-$(2)?=$(CC-$(platform))

$(bindir)/$(platformdir)-$(2)$($(3)-dirsuffix)/$(1)_%: $(srcdir)/$(1)/%.c $(common)
  mkdir -p $$(@D)
  $$(CC-$(platform)-$(2)) $(cflags) $($(3)-cflags) $(CFLAGS) -o $$@ $$^ $($(3)-ldflags) $(LDFLAGS)
endef

$(foreach library,$(libraries),\
  $(foreach arch,$(archs),\
    $(foreach configuration,$(configurations),\
      $(eval $(call build,$(library),$(arch),$(configuration))))))

In my case,

  • $(platform) is set to ‘mac
  • $(archs) consists in a single ‘x86+x64’ value
  • CC-mac-x86+x64 is set to ‘$(CC-mac) -arch i386 -arch x86_64

After having debugged that little beast for a while, I finally realized that $(common) contains both path to header (.h) and source (.c) files.

Inspecting the make invocation reveals something like:

cc -arch i386 -arch x86_64 -I/some/include/path -DSOME_MACRO -O2 -g -o out foo.c bar.c baz.c baz.h 

GCC swallows that without problems but apparently clang is totally confused.

The solution is to filter out header files from the list of files being compiled:

define build
CC-$(platform)-$(2)?=$(CC-$(platform))

$(bindir)/$(platformdir)-$(2)$($(3)-dirsuffix)/$(1)_%: $(srcdir)/$(1)/%.c $(MyCertificate.c) $(edk_c_src) $(common)
  mkdir -p $$(@D)
  $$(CC-$(platform)-$(2)) $(cflags) $($(3)-cflags) $(CFLAGS) -o $$@ $$(filter-out %.h,$$^) $($(3)-ldflags) $(LDFLAGS)
endef

See the $(filter-out pattern...,text) function in GNU Make’s manual.

Obvious right?! Hope it saves you precious minutes.