[CMake] Enabling C99 in CMake

Michael Hertling mhertling at online.de
Sat Jun 25 02:30:21 EDT 2011


On 06/23/2011 06:20 PM, Jed Brown wrote:
> On Thu, Jun 23, 2011 at 17:50, Michael Hertling <mhertling at online.de> wrote:
> 
>> You need to use a C99 compiler for your project
> 
> 
> This is already a problem. C99 introduces new keywords (e.g. restrict) and
> removes implicit int. It is entirely possible for part of a project to
> include C89-conforming legacy code that is not valid C99. The use of C99 or
> C89 should be a file- and directory-level property.

That's a really good point and could indeed be very well addressed by
a possibility for a project to enable language dialects per directory/
target/file as Todd has asked for in his initial posting. In order to
achieve this in a platform/compiler-independent manner, take a look at
the attached dialects.patch file, a diff against the Modules directory
of CMake 2.8.4. It is not meant as a production-ready solution, but as
as proof of concept, and it's restricted to the GNU C compiler, though
it should be easily applicable to the other compilers known by CMake.

First of all, the new Compiler/LanguageDialects.cmake file provides a
function __language_dialects() which accepts a language and a paired
list of arguments denoting each supported language dialect followed by
the flags to enable it. The function sets up the variable CMAKE_<LANG>_
DIALECTS_INIT containing the list of dialects, and for each dialect a
variable CMAKE_<LANG>_DIALECT_<DIALECT>_INIT containing the respective
flags. The Compiler/GNU-C.cmake file is enhanced to - exemplary - call

> __language_dialects(C C90 "-std=c90" C89 "-std=c89" C99 "-std=c99" C9X "-std=c9x" C1X "-std=c1x" ANSI "-ansi")

and the CMakeCInformation.cmake transfers these new variables to the
cache as it's done, e.g., for the CMAKE_C_FLAGS[_<CONFIG>] variables,
too. To see the results, apply the diff to the Modules directory and
configure the following project:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(DIALECT C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
MESSAGE("CMAKE_C_DIALECTS: ${CMAKE_C_DIALECTS}")
FOREACH(i IN LISTS CMAKE_C_DIALECTS)
  MESSAGE("CMAKE_C_DIALECT_${i}: ${CMAKE_C_DIALECT_${i}}")
ENDFOREACH()
FILE(WRITE ${CMAKE_BINARY_DIR}/c89.c "c89(){return 0;}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/c99.c "void c99(void *restrict p){}")
SET_SOURCE_FILES_PROPERTIES(${CMAKE_BINARY_DIR}/c89.c
    PROPERTIES COMPILE_FLAGS ${CMAKE_C_DIALECT_C89})
SET_SOURCE_FILES_PROPERTIES(${CMAKE_BINARY_DIR}/c99.c
    PROPERTIES COMPILE_FLAGS ${CMAKE_C_DIALECT_C99})
ADD_LIBRARY(c89 c89.c)
ADD_LIBRARY(c99 c99.c)

It issues the supported C dialects and the contents of the associated
dialect variables, and the c89.c and c99.c source files are compiled
with the correct flags. Of course, the CMAKE_C_DIALECT_<DIALECT>
variables can also be appended to the CMAKE_C_FLAGS[_<CONFIG>]
variables instead of the COMPILE_FLAGS source file property.

This turns out to be a simple and promising approach that

- provides the developers with platform/compiler-independent variables
  to check if the compiler accepts a certain dialect and to enable it,
- places the compiler-specific dialect flags in the compiler-specific
  files in the Modules/Compiler directory where they obviously belong,
- doesn't require complicated modifications in the Modules directory.

If you like this idea, feel free to add it to the feature request Todd
has filed in the meantime. However, while this approach is independent
of the dialects a compiler actually supports, be aware that mixed C89/
C90 projects to be built with CMake need *one* compiler which masters
C89 *and* C99, and that's not guaranteed for all of them.

> It's also horrible to encumber the poor user just trying to build your
> project with needing to know whether it is written in C99 or whatever else,
> nor with how to make their compiler deliver that dialect.

Once the CMake-detected or user-specified compiler isn't suitable for
the project, the user is in charge of choosing another one, and this
might happen quite quickly; it's sufficient that the compiler is not
in the PATH or unusually named. Then, the user must know whether the
project needs a C and/or C++ and/or Fortran compiler, and where it's
located. In such a situation, the need to know that a C99 compiler
is required does not make any further difference to the user, IMO.
In order not to be misunderstood: Of course, I appreciate measures
making the user's life easier, but I don't believe that choosing a
suitable compiler via the CC environment variable is something that
means an excessive demand for anyone.

> CMake does not ask the user to provide the full command to link a shared
> library, it should not require the user to specify dialect C99/C89.

The command to link a shared library is determined by the compiler, so
there is typically no freedom to chose beyond the parameterization and
usually, there's no need to choose. Contrary to this, a project - with
a requirement for a particular dialect or not - isn't a priori related
to a compiler, but the user is free to choose, and this is why I think
that the two above-mentioned examples are different things. Anyway, a
C99 project that activates the compiler's C99 dialect by itself would
be convenient - provided the compiler supports it - and I do not want
to oppose this at all, but if I can successfully built a C99 project
via a simple CC="gcc -std=c99", it works for me. As I said in one of
my previous postings, that's just my personal opinion, and of course,
one can take up a different position.

Regards,

Michael
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dialects.patch
Type: text/x-diff
Size: 1885 bytes
Desc: not available
URL: <http://www.cmake.org/pipermail/cmake/attachments/20110625/cf190e2a/attachment.patch>


More information about the CMake mailing list