In short, what is the final textual state of a valid DTS file after it has been run through the C preprocessor? Exactly what should be left behind from #include
directives? How much of this is dtc
supposed to tolerate? Did the Linux headers have to be specially laid out to support inclusion in a DTS file?
For fun and profit, I am adding device tree support to a FreeRTOS project. In doing so, I need to add build support to actually generate and embed my DTB into the final binary. The first step is to run the preprocessor on the DTS to convert C definitions. This preprocessed DTS is then fed to dtc
to create the final DTB.
I have all of the build integration and such working but I am getting tripped up by the preprocess step. I have seen numerous posts online which all are a variation on the arguments specified here; my specific incantation (I am using CMake currently) is:
"${CMAKE_C_COMPILER}" "-D$<JOIN:$<TARGET_PROPERTY:${COMPONENT_LIB},COMPILE_DEFINITIONS>,$<SEMICOLON>-D>"
"-I$<JOIN:$<TARGET_PROPERTY:${COMPONENT_LIB},INCLUDE_DIRECTORIES>,$<SEMICOLON>-I>"
-E -P --undef __ASSEMBLER__ -x assembler-with-cpp -o "${CURRENT_DTS_PREPROCESS}" "${CURRENT_DTS}"
This command completes successfully but the subsequent dtc
step fails to parse the preprocessed DTS with syntax errors. If I examine these errors, they are all on C declarations that would survive the proprocessor. For example, here are the first couple of lines of the preprocessed output:
/dts-v1/;
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef short int __int16_t;
typedef short unsigned int __uint16_t;
typedef int __int32_t;
typedef unsigned int __uint32_t;
typedef long long int __int64_t;
...
Presumably the first include file to be considered is stdint.h
or similar, hence the definitions for all of the fixed-width types first. The first syntax error reported by dtc
is /path/to/dts.preprocess:4.1-8 syntax error
which exactly corresponds to the first typedef
token (with trailing space).
So, should the device tree compiler be tolerant of this or am I missing something in my incantation to elide all C definitions that aren't #define
substitutions? Or is there something else at work here?
Per discussion on the Linux Kernel Mailing List as well as @JohnBollinger's and @sawdust's comment, it looks like the Linux headers had to be specifically laid out to support inclusion into a device tree. Specifically, they were intentionally set up to not contain C directives which are not valid DTS syntax. Bummer.
Near as I can tell, the only way to do this without duplicating / reworking headers would be ANOTHER process step after the C preprocessor but before dtc
invocation to strip out the leftover C gunk. This is left as an exercise for the reader.