Exclude go source files by architecture when compiling - compilation

I am writing a Go program for Windows which contains several packages. One of these packages is using CGo to call a few functions defined in some .h and .c files. These .c files are dependent on windows.h .
Since developing on the Windows platform is incredibly tedious I would like to make a mockup of the functions in this file and develop on Linux instead. But when I try to compile I get:
fatal error: windows.h: No such file or directory
Since the go tool tries to compile my Windows dependent files. Is there some way around this? I know that putting something like
#ifdef ..
import x
#endif
is not best practice but in this case I need something to allow compiling only the "Linux" files.

Quoting from the build constraints documentation:
A build constraint is a line comment beginning with the directive +build that lists the conditions under which a file should be included in the package. Constraints may appear in any kind of source file (not just Go), but they must appear near the top of the file, preceded only by blank lines and other line comments.
To distinguish build constraints from package documentation, a series of build constraints must be followed by a blank line.
A build constraint is evaluated as the OR of space-separated options; each option evaluates as the AND of its comma-separated terms; and each term is an alphanumeric word or, preceded by !, its negation. That is, the build constraint:
// +build linux,386 darwin,!cgo
corresponds to the boolean formula:
(linux AND 386) OR (darwin AND (NOT cgo))
A file may have multiple build constraints. The overall constraint is the AND of the individual constraints. That is, the build constraints:
// +build linux darwin
// +build 386
corresponds to the boolean formula:
(linux OR darwin) AND 386
During a particular build, the following words are satisfied:
the target operating system, as spelled by runtime.GOOS
the target architecture, as spelled by runtime.GOARCH
the compiler being used, either "gc" or "gccgo"
"cgo", if ctxt.CgoEnabled is true
"go1.1", from Go version 1.1 onward
any additional words listed in ctxt.BuildTags
If a file's name, after stripping the extension and a possible _test suffix, matches any of the following patterns:
*_GOOS
*_GOARCH
*_GOOS_GOARCH
(example: source_windows_amd64.go) or the literals:
GOOS
GOARCH
(example: windows.go) where GOOS and GOARCH represent any known operating system and architecture values respectively, then the file is considered to have an implicit build constraint requiring those terms.
To keep a file from being considered for the build:
// +build ignore
(any other unsatisfied word will work as well, but “ignore” is conventional.)
To build a file only when using cgo, and only on Linux and OS X:
// +build linux,cgo darwin,cgo
Such a file is usually paired with another file implementing the default functionality for other systems, which in this case would carry the constraint:
// +build !linux,!darwin !cgo
Naming a file dns_windows.go will cause it to be included only when building the package for Windows; similarly, math_386.s will be included only when building the package for 32-bit x86.

Related

Building static Armadillo using OpenBLAS, ARPACK, LAPACK, and SuperLU

We have an HPC environment with multiple versions of most packages, causing us to have designed a home-rolled way to install packages in unique locations and use environment modules for programmers/researchers to be able to identify which library versions they are using when they build a program, run a program, or both. Is there a relatively painless way to be able to perform builds in this environment. In my case, we're using OpenBLAS, ARPACK, LAPACK and SuperLU when building armadillo. In my case, I'm shooting for armadillo-0.3.7. It would be real nice if the use of switches as was done in the ./configure and make days would work. But all I've found so far is CMake builds, and it appears to be pretty much non-trivial to do a build.
Oh yeah. And, by the way, there's a need for the output Armadillo library to be static.
Thanks in advance for your help. The initial question may be a little vague, but I can get as specific as you like. I just didn't want to write a novel for the initial question on this issue.
Tools exist nowadays to handle the complexity of the build of these scientific software. I would suggest you look at either Spack or EasyBuild. Such tool will help you to save a lot of time by automatically building all the required dependencies and also generating the modulefiles for your users to use the software built.
The CMakeList.txt file and other CMake-related files can be modified to meet your needs. The flags are defined on line 48+, for instance set(ARMA_USE_LAPACK false)
The variables related to the LAPACK library are then defined in the include(ARMA_FindLAPACK) on line 250. The flag in toggled on on line 347 if lapack is found.
The customized path where LAPACK is located can be specified in the file cmake_aux/ARMA_FindLAPACK.cmake. If your customized path is stored as an environment variable as export PATHLAPACKLIB=/usr/lib/openblas-base, you can use it in the ARMA_FindLAPACK.cmake file by modifying line 11 ( see How to retrieve a user environment variable in CMake (Windows) and FIND_LIBRARY()):
message("Searching Lapack in $ENV{PATHLAPACKLIB}")
FIND_LIBRARY(LAPACK_LIBRARY
NAMES ${LAPACK_NAMES}
HINTS $ENV{PATHLAPACKLIB}
NO_DEFAULT_PATH
)
It is not a beautiful modification of the CMakefile, because it makes it not portable as its outcome depends on an environment variable. But, it you intend to to build and install Armadillo once for all, it works. Remember to delete the CMakeCache.txt file every time you modify a CMakeFile.txt, otherwise it keeps some trace of previous runs of cmake . and it looks as though the modification is consequenceless.
To make the library static, add the keyword static to the command add_library() on line 514 of CMakeFile.txt, as shown in CMake - Creating a static library :
add_library( armadillo STATIC ...)
Running cmake . and then make creates a small armadillo.a file, since most of the source consists in cpp headers.
Finally, the exemple1 is compiled as :
g++ -O2 -std=c++11 example1.cpp -o example1 -larmadillo -L/home/...../softs/armadillo-9.800.3/armadillo-9.800.3 -I/home/...../softs/armadillo-9.800.3/armadillo-9.800.3/include -lopenblas

Autotools: GCC's Makefile.in has a bug (7.3.0 and earlier). How to re-program automake to find 'ar' and 'objdump'

GCC's cross compiling autotools is supposed to be flexible, but I've isolated a bug that's been breaking cross compiler builds that ought to work.
Note: Some systems will "poison" default compiler tool names to prevent using wrong tools by default. On my system, x86_64-pc-gnu-linux-ar will execute but "ar" is not found.
I need to build cross compiler toolchains with custom names. gcc's configure script supports this with --program-prefix or --program-transform-name. However, when using a custom name, all compile time tools have to be explicitly named on the configure line. gcc configure is not intelligent enough to find tools it has just built with a name change. (too stupid).
The GCC manual states how to explicitly name tools:
configure AR=x86_foo_b_ar AR_FOR_TARGET=ARMv6m_foo_b_ar ...
However, it doesn't work right. Autoools sometimes ignores the supplied names and the build fails. In particular, it ignores 'AR' and 'OBJDUMP' variables.
Apparently the toplevel gcc configure was created at a later date than lower level configures.
Makefile.in without Makefile.am in GCC?
Makefile.am does not exist in some subdirectories, but it does exist in newer subdirectories.
This causes inconsistencies in variable passing from the top-level makefile.
Internally, the top level "configure" script has variables AR_FOR_HOST (alias for AR), AR_FOR_BUILD, and AR_FOR_TARGET. These variables are used to re-define "AR" when entering sub-directories to force a generic make script to compile for a particular target.
I've even gone so far as to define the internal variables correctly as well as "AR" and "OBJDUMP" on the configure command line. ( Shouldn't be needed ).
gcc-7.3.0/configure --host=x86_64-pc-linux-gnu --program-prefix=armv6m-softfloat-eabi-newlib- AR_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-ar AR=/usr/bin/x86_64-pc-linux-gnu-ar AR_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-ar AR_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/ar AS_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-as AS=/usr/bin/x86_64-pc-linux-gnu-as AS_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-as AS_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/as DLLTOOL_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/dlltool LD_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-ld LD=/usr/bin/x86_64-pc-linux-gnu-ld LD_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-ld LD_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/ld LIPO_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/lipo NM_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-nm NM=/usr/bin/x86_64-pc-linux-gnu-nm NM_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-nm NM_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/nm OBJCOPY_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-objcopy OBJCOPY=/usr/bin/x86_64-pc-linux-gnu-objcopy OBJCOPY_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-objcopy OBJCOPY_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/objcopy OBJDUMP_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-objdump OBJDUMP=/usr/bin/x86_64-pc-linux-gnu-objdump OBJDUMP_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-objdump OBJDUMP_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/objdump RANLIB_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-ranlib RANLIB=/usr/bin/x86_64-pc-linux-gnu-ranlib RANLIB_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-ranlib RANLIB_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/ranlib READELF_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-readelf READELF=/usr/bin/x86_64-pc-linux-gnu-readelf READELF_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-readelf READELF_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/readelf STRIP_FOR_BUILD=/usr/bin/x86_64-pc-linux-gnu-strip STRIP=/usr/bin/x86_64-pc-linux-gnu-strip STRIP_FOR_HOST=/usr/bin/x86_64-pc-linux-gnu-strip STRIP_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/strip CC_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/cc CXX_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/cxx WINDRES_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/windres WINDMC_FOR_TARGET=/usr/libexec/gcc/armv6m-softfloat-eabi-newlib/windmc --target=armv6m-softfloat-eabi --build=x86_64-pc-linux-gnu --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/armv6m-softfloat-eabi-newlib/gcc-bin/7.3.0 --includedir=/usr/lib/gcc/armv6m-softfloat-eabi-newlib/7.3.0/include --datadir=/usr/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0 --mandir=/usr/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0/man --infodir=/usr/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0/info --with-gxx-include-dir=/usr/lib/gcc/armv6m-softfloat-eabi-newlib/7.3.0/include/g++-v7 --with-python-dir=/share/gcc-data/armv6m-softfloat-eabi-newlib/7.3.0/python --enable-languages=c --enable-obsolete --enable-secureplt --disable-werror --with-system-zlib --enable-nls --without-included-gettext --enable-checking=release --with-bugurl=https://bugs.gentoo.org/ --with-pkgversion=Gentoo 7.3.0-r3 p1.4 --disable-esp --enable-poison-system-directories --disable-bootstrap --with-newlib --enable-multilib --disable-altivec --disable-fixed-point --with-float=soft --disable-libgcj --disable-libgomp --disable-libmudflap --disable-libssp --disable-libcilkrts --disable-libmpx --disable-vtable-verify --disable-libvtv --disable-libquadmath --enable-lto --without-isl --disable-libsanitizer --enable-default-pie --enable-default-ssp
I'm wanting gcc to both make and use tools that start with the prefix: armv6m-softfloat-eabi-newlib-
(Arm cortex m0 chipset is what I am using)
But "make" still fails when attempting to execute "ar" in the .../libcpp directory. The reason is that .../libcpp/Makefile.in is not updated by automake. It's a hand crafted file. On line 28 of the old .../libcpp/Makefile.in it says "AR = ar"
So, the AR variable is hardcoded to "ar" But, "ar" doesn't exist on my system. I've tried editing .../libcpp/Makefile.in with "AR = dummyname" , and the build crashes with "can't fine dummyname" instead of can't find "ar". So, the bug is on line 28.
All other variables in the .../libcpp/Makefile.in are of the form:
CC = #CC#
INSTALL = #INSTALL#
etc..
On a positive note: The compiler used by .../libcpp IS the fully qulaified name I gave to gcc-7.3.0/configure. That success made me think I could fix the bug by editing the makefile to read:
AR = #AR#
But the build fails with "Can't find AR#"
I'm not familiar enough with autotools to hand edit the Makefile.in and fix the bug.
What's the #variable# name format do?
Does the configure.ac in the subdirectory have to define "AR" in some way for #AR# to be linked to the value in the toplevel directory?
I've tried a few other tests while building different gcc versions. Re-running autoconfig, automake, is hell because GCC uses AC_PREREQ() macro.
For example, I have autotools 2.69 installed ... but gcc 7.3.0 fails and complains that I must use autotools 2.64, ONLY. eg: AC_PREREQ(2.64)
So, fixing the bug via autotools doesn't seem practical.
I'm hoping to simply patch the .../libcpp/Makefile.in, since that file is exactly the same in so many versions of gcc.
Questions:
Why is "ar" hard-coded ? Is this a serious legacy issue? and what is a minimal patch that won't interfere with other configurations of GCC?
Is it better to modify the shell or the Makefile; eg: like the top level configure shell script could define a bash function that would be inherited by make as "if" it were a program.
if [ -z ${AR##*-*} ] ; then
ar() { $AR }
fi
Edit: A quick-fix patch for gcc-7.3.0
This is not a "correct" fix, but just a work-around.
I've found three places where the sub-directories ignore variables passed in from the toplevel configure.
.../libcpp/Makefile.in on line 29
.../gcc/configure just before line 29531
.../libcc1/configure just before 14574
The second and third errors are from a defective macro in configure.ac. I haven't traced it back because I can't run autoconfig anyway.
I added a line to the configure(s), to see if passing the default OBJDUMP override variable would allow gcc to compile. It does. I'm not sure I've chosen the right override variable for all cases of gcc compile switches, but at least it proves where the bug is.
Patch file follows:
--- gcc-old/libcpp/Makefile.in
+++ gcc-new/libcpp/Makefile.in
## -28,3 +28,3 ##
INSTALL = #INSTALL#
-AR = ar
+AR ?= ar
ARFLAGS = cru
--- gcc-old/gcc/configure
+++ gcc-new/gcc/configure
## -29531,4 +29531,6 ##
;;
esac
+ if [ -n $OBJDUMP ]; then export_sym_check="$OBJDUMP -T"; fi
+
if test x"$enable_plugin" = x"yes"; then
--- gcc-old/libcc1/configure
+++ gcc-new/libcc1/configure
## -14574,4 +14574,6 ##
;;
esac
+ if [ -n $OBJDUMP ]; then export_sym_check="$OBJDUMP -T"; fi
+
if test x"$enable_plugin" = x"yes"; then
TL;DR: there are a lot of things you could try, but the very first would be to specify AR on the command line when you run make:
make AR=x86_foo_b_ar
That shouldn't be necessary when you've already specified the same to configure, but if it doesn't work then that suggests a problem one or more levels up from the Makefile.in you're looking at. Variable definitions specified on the make command line override definitions in makefiles.
"make" still fails when attempting to execute "ar" from the .../libcpp directory. The reason is that .../libcpp/Makefile.in is not updated by automake. It's a hand crafted file.
To be clear, since understanding the system you are trying to use is immensely helpful in troubleshooting it, automake does not run at configuration or build time. It is used by the package maintainer to build one or more Makefile.in files to be included in source distributions, such as the one you obtained. Of course, this is not the only way to create Makefile.in files, and the configure script does not care how you create them (or other input files).
I'm not familiar enough with autotools to hand edit the Makefile.in and fix the bug. What's the #variable# name format do?
Does the configure.ac in the subdirectory have to define "AR" in some way for #AR# to be linked to the value in the toplevel directory?
The #variable# construction is used for values that are expected to be substituted by the configure script when it builds a corresponding output file. For that to take place, there needs to be at least a corresponding AC_SUBST([variable]) or its equivalent in the configure.ac (sometimes named configure.in, instead). Normally, that's preceded somewhere in configure.ac by code assigning an appropriate value to shell variable variable.
If you modify configure.ac then you need to rebuild the configure script, and in that case it's probably safest to rebuild the whole build system, as a package maintainer would do. There may be a script provided for that purpose in the package (autogen.sh is a common name for such scripts), but the default mechanism is to run the Autotools program autoreconf in the top-level directory of the project source tree.
I've tried a few other tests while building different gcc versions.
Re-running autoconfig, automake, is hell because GCC uses AC_PREREQ()
macro.
For example, I have autotools 2.69 installed ... but gcc 7.3.0 fails
and complains that I must use autotools 2.64, ONLY. eg:
AC_PREREQ(2.64)
That description is not consistent with the documentation of AC_PREREQ, nor with my experience with that macro. AC_PREREQ tests for the specified Autoconf version or newer. It does not demand an exact Autoconf version. There may be something else in the build system that does so, but it's not AC_PREREQ.
In any case, one alternative would be to obtain and install Autoconf 2.64. You may even be able to install it alongside your existing version. Some systems even provide pre-built packages for exactly that purpose.
So, fixing the bug via autotools doesn't seem practical. I'm hoping to
simply patch the .../libcpp/Makefile.in, since that file is exactly
the same in so many versions of gcc.
Patching a Makefile.in does not require afterward re-running the autotools, so it's at least conceivable that that would work. Even for Makefile.in files that were generated by Automake. You could consider having a look at how AR is defined in some of the Automake-generated Makefile.in files in the project (supposing there are any) for an idea of how it should look.
Why is "ar" hard-coded ? Is this a serious legacy issue?
I can only speculate. As a threshold matter, I'm inclined to suppose that in that Makefile, the archiver of the build system is the one wanted (not that of the intended host system, nor a cross-ar for host-target). It is reasonable in that case for AR = ar to be provided as a default, because that can be overridden via a declaration of that variable on the command-line.
That you are in fact not getting the AR you specify to configure looks like a bug to me -- probably a regression introduced at some point when some of the higher-level bits of the build system were updated. I have no trouble imagining such an issue slipping by, as a system configuration such as yours, in which the system's own archiver goes only by a non-standard name, is very uncommon.
and what is a
minimal patch that won't interfere with other configurations of GCC?
The first thing to try is to pass the AR definition on the top-level make command line:
make AR=x86_foo_b_ar
Such definitions will be passed on to recursively-invoked sub-makes, and definitions on the command line (but not, by default, from the environment) override definitions in Makefiles.
Is it better to modify the shell or the Makefile; eg: like the top
level configure shell script could define a bash function that would
be inherited by make as "if" it were a program.
The top-level configure script could be modified to define a shell function and export it to child processes, but not to its parent or siblings. This is nothing specific to configure; the shell just doesn't work that way. Whatever changes you make, if any, would be best made in Makefile.in files before running configure, or in the generated Makefiles afterward.

CMake: generate and compile architecture-specific source files in XCode

I have a CMake project that's used to generate an iOS-targeted XCode project that supports multiple CPU architectures (arm64 and armv7).
My CMake project includes some commands (defined with add_custom_command) that convert Lua scripts into C++ source files. These generated C++ files differ by architecture (the armv7 file should not be compiled for arm64 and vice versa).
The tool meant to be invoked like this:
./data_tool --input <script> --output <C++ source> --architecture <armv7 or arm64>
My (incorrect) CMake file currently looks something like this:
foreach(ARCHITECTURE ${TARGET_ARCHITECTURES})
string(
REPLACE ".lua" ".cpp" GENERATED_CPP
${GENERATED_SOURCE_DIRECTORY}/${ARCHITECTURE}/${INPUT_SCRIPT}
)
add_custom_command(
OUTPUT ${GENERATED_CPP}
COMMAND ${DATA_TOOL} --input "${INPUT_SCRIPT}" --output "${GENERATED_CPP}" --architecture ${ARCHITECTURE}
MAIN_DEPENDENCY ${INPUT_SCRIPT}
)
list( APPEND GENERATED_SOURCE ${GENERATED_CPP} )
endforeach()
Later, GENERATED_SOURCE is appended to the source file list passed to add_executable. This code is obviously wrong because both the armv7 and arm64 files are compiled when building for either architecture.
How can I tell CMake that each architecture compiles a different set of source files?
XCode doesn't have a great way to exclude files based on the architecture being built. While it is possible (see Disabling some files in XCode project from compilation), setting this up via CMake is going to be somewhat difficult.
Instead, I would suggest simply making your generation tool/script put preprocessor guards around the entire file, for the architecture that the generated file supports. That way, when XCode compiles them, they will be essentially empty, except for the architecture that they are meant for. In this answer (Determine if the device is ARM64), it shows how you can do a conditional compile based on arm64 (and use the reverse for armv7).
Well, don't put generated sources for different arches into the same list. Unwrap foreach body and just repeat these commands for each arch.
If you don't want to introduce code duplication, you can write a CMake function that creates that custom command and returns a list of generated sources. See this question for how to return values from functions.

Why do gcc and clang silently allow a standard include file to redefine macros?

Example code:
#define PROT_NONE 99
#include <sys/mman.h>
Both gcc and clang permit the above code fragment to compile; the PROT_NONE macro is redefined from within sys/mman.h with no warning. Looking at the actual header file, there is no #undef which would permit a redefinition.
This seems like a problem -- although this case is obviously contrived to show the problem, it does seem that identifier collisions between my code and the system header files can be silently ignored. The system header definition of PROT_NONE overrides my definition and doesn't even warn me that there's a potential problem. This seems to be specific to the system header file somehow; if I try to do the redefinition myself, I get the proper error.
My question is basically twofold:
Does anybody know the motivation behind allowing this behavior?
Is there any command line switch that will cause this to fail at the compilation stage?
What's happening/motivation
In both gnu and clang, warnings are suppressed in system headers.
The clang user manual just declares this is so:
Warnings are suppressed when they occur in system headers.
...but the gnu c preprocessor manual gives the following justification:
The header files declaring interfaces to the operating system and runtime libraries often cannot be written in strictly conforming C. Therefore, GCC gives code found in system headers special treatment.
Mitigation on the command line
Is there any command line switch that will cause this to fail at the compilation stage?
Yes. Make your system-headers non-system-headers.
In clang, you can do this merely with --no-system-header-prefix x/y/z, where x/y/z is a pattern matched starting at all system directories. For example, in your case, you can use --no-system-headers sys; or you can cherry pick further: --no-system-headers sys/mm (all files in a system directory included via the sys subdirectory that start with mm; it's just a prefix pattern, not a directory spec).
In gcc, this is a bit tricker. System headers by default are just headers in system directories, and there's no way to exclude a particular directory as a system directory. You can, however, ditch all system directories with -nostdinc, and add them back in as regular inclusion directories. For example:
gcc -nostdinc -I/usr/include -I/usr/lib/gcc/x86_64-pc-cygwin/5.4.0/include ...
You need -nostdinc; -I paths into your system inclusion paths just winds up being ignored.
GCC suppresses warnings in system headers by default. The reason is that the user usually cannot do anything about warnings generated by those headers because they cannot edit the code to fix those warnings. You can enable those warnings using -Wsystem-headers.
For your specific example, a redefinition of a macro not defined in a system header by a system header, GCC should probably warn even with -Wno-system-headers (it now has the infrastructure to do that). Someone already filed an RFE:
-Wno-system-headers hides warning caused by user header vs system header conflict

Using CMake to resolve #include dependencies in an exotic language

I'm trying to use CMake as my build tool driver (I make it clear at once that I'm quite new to CMake since this my first on-my-own CMake project). My project is mainly C with some files in an exotic language I'll call here Z. These Z files must be processed by their Z compiler to produce .h and .c files.
I managed to tweak CMake handle Z compiling and dependencies between plain C files and generated Z -> .h header with
add_custom_command( ...*details omitted*... )
set_source_file_properties(*generated-.h* PROPERTIES GENERATED TRUE)
and CMake C-#include scanner does properly the rest of the job.
Now, Z files use something equivalent to C #include construct and I'd like to make profit of automatic recompilation when one of the Z-included files changes.
If a.Z includes inc.Z, I tried:
set_source_file_properties(a.Z PROPERTIES OBJECT_DEPENDS inc.Z)
but that doesn't trigger automatic recompilation of a.Z.
CMake manual says this property was introduced for this purpose and is no longer necessary for C/C++. However it is ineffective in my Z case.
If I modify my custom command as follows:
add_custom_command( ... DEPENDS inc.Z ...)
I get the desired result, but not all Z files depend on inc.Z (another one might depend on inc2.Z).
I then tried to generate dynamically the DEPENDS list with
get_source_file_property(dependencies ${filename} OBJECT_DEPENDS)
if(dependencies STREQUAL "NOTFOUND")
unset(dependencies)
else()
string(REPLACE ";" " " dependencies "${dependencies}")
endif()
add_custom_command(... DEPENDS $filename "$dependencies" ...)
and make errors out with
Make[2]: *** no rules to build target `-- content of dependencies variable --'
Note: error is the same with or without double quotes around variable substitution
I guess CMake interpreted my list of dependencies as a single (non-existent) filename and make was unable to handle that. Anyway, the files mentionned in the dependencies variable are not meant to be compiled, only to be included somewhere. They must make their way to make only as dependencies.
Which direction should I go to achieve the desired result?
Recall this is my first on-my-own CMake project and I certainly made newbie errors.
FWIW, my platform is Linux with CMake 2.8.9 (not bleeding edge but I'm only exploring) and KDevelop 4.x
Thanks for your help.

Resources