Kernel module compilation and KBUILD_NOPEDANTIC

dimba picture dimba · Jun 18, 2012 · Viewed 13.7k times · Source

I've noticed that recent kernels (starting from 2.16.24?) don't like if CFLAGS is changed in external module Kbuild file. If CFLAGS is changed you'll be issued the following error by Linux kernel Kbuild system:

scripts/Makefile.build:46: *** CFLAGS was changed in "/some/path". Fix it to use EXTRA_CFLAGS.  Stop.

From here:

External modules have in a few cases modifed gcc option by modifying CFLAGS. This has never been documented and was a bad practice.

Additional email from LKML.

Why is it bad idea? What is rational?

Answer

Reinier Torenbeek picture Reinier Torenbeek · Jun 28, 2012

First of all, it might be worth mentioning that EXTRA_CFLAGS has been deprecated a while ago and is replaced by ccflags-y. You can read about the intention of ccflags-y in Documentation/kbuild/makefiles.txt, section 3.7.

Basically, this variable allows you to append settings to the set of C compilation flags, within the scope of the file where it is assigned only. You are not supposed to change the global flags, because that might have a global impact beyond your own makefile, which is considered bad practice. The check that you mention verifies that indeed, the global flags did not get changed by included makefiles.

It is interesting to check out how ccflags-y, formerly known as EXTRA_CFLAGS, ends up being used in the build process. Tracing some relevant points (but not all, because that is left as an exercise to the reader ;-) ) shows the following:

EXTRA_CFLAGS can still be used, according to scripts/Makefile.lib

1 # Backward compatibility
2 asflags-y  += $(EXTRA_AFLAGS)
3 ccflags-y  += $(EXTRA_CFLAGS)

The same file shows how ccflags-y ends up in the C compilation flags (and also shows you that you have another variable at your disposal, called CFLAGS_<filename>.o):

104 orig_c_flags   = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \
105                  $(ccflags-y) $(CFLAGS_$(basetarget).o)
106 _c_flags       = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags))
...
133 __c_flags       = $(_c_flags)
...
147 c_flags        = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE)     \
148                  $(__c_flags) $(modkern_cflags)                           \
149                  -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags)

Then in scripts/Makefile.build, the compilation rule is defined:

234 cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<

Note that these are all recursively expanded variables, using = and not :=, which means that your own value of ccflags-y gets inserted into the C flags when you define it in your own makefile.

Finally about KBUILD_NOPEDANTIC, which you mention in the title but not in the actual question. This test for changed value of CFLAGS can be disabled by giving KBUILD_NOPEDANTIC any value -- see scripts/Makefile.build

47 ifeq ($(KBUILD_NOPEDANTIC),)
48         ifneq ("$(save-cflags)","$(CFLAGS)")
49                 $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y)
50         endif
51 endif

The files referenced in this answer were all retrieved today.

Now... not being an expert in this area and looking further into the makefiles after writing this whole story down, there is a thing that I do not understand either. It seems to me that CFLAGS is not used in the build system (not implicitly, nor explicitly), but KBUILD_CFLAGS is. So I wonder whether this check for changes in CFLAGS should actually be a check for changes in KBUILD_CFLAGS instead.