[CMake] OpenMP detection/support

Crni Gorac cgorac at gmail.com
Sat Jul 29 15:03:02 EDT 2006


On 7/29/06, William A. Hoffman <billlist at nycap.rr.com> wrote:
> I am not sure what makes a compiler OpenMP compatible, but you can
> use TRY_COMPILE and TRY_RUN to test code fragments.   Most likely that
> is what your autotools stuff was doing.  It should be pretty easy
> to move the autotools over to cmake.   CMake is very good at having cmake
> time options.  The SET, IF, and OPTION commands would be worth looking at.
>
> http://www.cmake.org/HTML/Documentation.html
>
> That should be a good start, if you have more specific questions, just post them.
>

Thanks for prompt reply, and sorry if my message was confusing a bit -
I'm still at my day one with cmake.  I decided in the meantime to
start with converting slightly simpler project, this one using MPI,
from autotools to cmake, and here follow some experiences (I'm writing
this in detail mostly because of flex/bison stuff, I was able to found
only one message, dated 2002, on this list discussing this kind of
stuff, so maybe setup I found working will be useful to someone else;
btw, it would be probably very helpful if you could somewhat improve
search interface to this list) with some additional questions.

Everything in my project, let's call it "foo", in pure ANSI C, except
that I'm using flex and bison for parsing input, then I need getopt()
function for processing program command line options and finally, I'm
using MPI library.  Source code files are distributed between foo/lib
directory, where "libfoo" library was generated, and foo/src
directory, where executable "foo" was generated.  My first question is
related exactly to these names, I wasn't able to find how to have a
library named "libfoo" and an executable named "foo" with cmake in
same project, so I had to rename executable to "bar"; thus my first
question would be: is something alike somehow possible with cmake?


Since MPI functions are used from both library and executable, I
started with following CMakeLists.txt in my project root directory
(basically, I'm defining project name, then adding foo/lib directory
to list of include files and libraries search directories of my
project, and finally am checking for MPI library (with some printouts
added) and adding MPI include directory to list of include files
search directories of my project and am also remembering MPI linker
flags to be used later:

###################
PROJECT(foo)
SUBDIRS(lib src)

INCLUDE_DIRECTORIES(${foo_SOURCE_DIR}/lib)
LINK_DIRECTORIES(${foo_BINARY_DIR}/lib)

SET(mpiLibrary)
SET(MPI_INCLUDE_PATH)
SET(MPI_LIBRARY)
MESSAGE(
  STATUS
  "Check for working MPI library..."
)

FIND_PACKAGE(MPI)
IF(MPI_INCLUDE_PATH STREQUAL "" OR MPI_LIBRARY STREQUAL "")
  MESSAGE(
    FATAL_ERROR
    "MPI library was not found on the system."
  )
ENDIF(MPI_INCLUDE_PATH STREQUAL "" OR MPI_LIBRARY STREQUAL "")

INCLUDE_DIRECTORIES(  ${MPI_INCLUDE_PATH})
SET(mpiLibrary ${mpiLibrary} ${MPI_LIBRARY})
MESSAGE(
  STATUS
  "Check for working MPI library: found"
)
###################


Now, in my foo/lib directory, I have another  CMakeLists.txt file, as
follows. First, I'm definining foo_SRCS variable to hold all .c file
names in this directory, and then am checking (again with some
printouts added) for bison and flex, and then am defining custom
commands for compiling my flex scanner (with source code in
foo/lib/scanner.l file) and bison parser (with source code in
foo/lib/parser.y file), that are parts of the library.  Finally, I'm
adding generated C code for parser and scanner (files scanner.c and
parser.c) into foo_SRCS variable, am adding directory where these
files are generated into list of my project include files search
directories (because bison will generate parser.h file too, that is
going to be included from scanner.c), and then am specifying that
"libfoo" library should be created from the list of files enumerated
in foo_SRCS variable).

###################
SET(
  foo_SRCS
  file1.c
  file2.c
# etc.
)

SET(BISON bison)
MESSAGE(
  STATUS
  "Check for working \"${BISON}\" parser generator..."
)
FIND_PROGRAM(BISON_EXECUTABLE ${BISON})

SET(BISON_FOUND 0)
IF(EXISTS ${BISON_EXECUTABLE})
  SET(BISON_FOUND 1)
ENDIF(EXISTS ${BISON_EXECUTABLE})
IF(NOT ${BISON_FOUND})
  MESSAGE(
    FATAL_ERROR
    "\"${BISON}\" was not found on the system."
  )
ENDIF(NOT ${BISON_FOUND})
MESSAGE(STATUS "Check for working \"${BISON}\" parser generator: found")

SET(FLEX flex)
MESSAGE(
  STATUS
  "Check for working \"${FLEX}\" lexical analyzer generator..."
)
FIND_PROGRAM(FLEX_EXECUTABLE ${FLEX})

SET(FLEX_FOUND 0)
IF(EXISTS ${FLEX_EXECUTABLE})
  SET(FLEX_FOUND 1)
ENDIF(EXISTS ${FLEX_EXECUTABLE})
IF(NOT ${FLEX_FOUND})
  MESSAGE(
    FATAL_ERROR
    "\"${FLEX}\" was not found on the system."
  )
ENDIF(NOT ${FLEX_FOUND})
MESSAGE(
  STATUS
  "Check for working \"${FLEX}\" lexical analyzer generator: found"
)

ADD_CUSTOM_COMMAND(
  OUTPUT ${foo_BINARY_DIR}/lib/parser.c
  COMMAND ${BISON_EXECUTABLE}
  ARGS -d -o ${foo_BINARY_DIR}/lib/parser.c ${foo_SOURCE_DIR}/lib/parser.y
  DEPENDS ${foo_SOURCE_DIR}/lib/parser.y
)

ADD_CUSTOM_COMMAND(
  OUTPUT ${foo_BINARY_DIR}/lib/scanner.c
  COMMAND ${FLEX_EXECUTABLE}
  ARGS -o${foo_BINARY_DIR}/lib/scanner.c ${foo_SOURCE_DIR}/lib/scanner.l
  DEPENDS ${foo_SOURCE_DIR}/lib/scanner.l ${foo_BINARY_DIR}/lib/parser.h
)

SET(foo_SRCS ${foo_SRCS} ${foo_BINARY_DIR}/lib/parser.c)
SET_SOURCE_FILES_PROPERTIES(${foo_BINARY_DIR}/lib/parser.c GENERATED)

SET(foo_SRCS ${foo_SRCS} ${foo_BINARY_DIR}/lib/scanner.c)
SET_SOURCE_FILES_PROPERTIES(${foo_BINARY_DIR}/lib/scanner.c GENERATED)

INCLUDE_DIRECTORIES(${foo_BINARY_DIR}/src)

ADD_LIBRARY(foo SHARED ${foo_SRCS})
###################


Another CMakeLists.txt file is created into foo/src directory, with
contents as follows.  This one is simple - I'm first checking for
getopt() function, than am definining source code file that my "bar"
executable should be compiled from, and am finally stating that the
executable should be linked with my "libfoo" library, then with MPI
library and with libm (because I'm using functions from <math.h>).

###################
INCLUDE(CheckFunctionExists)
SET(GETOPT getopt)
CHECK_FUNCTION_EXISTS(${GETOPT} GETOPT_FOUND)
IF(GETOPT_FOUND STREQUAL "")
  MESSAGE(
    FATAL_ERROR
    "\"${GETOPT}\" function was not found on the system."
  )
ENDIF(GETOPT_FOUND STREQUAL "")

ADD_EXECUTABLE(
  bar
  file1.c
  file2.c
# etc.
)

TARGET_LINK_LIBRARIES(bar foo ${mpiLibrary} m)
###################


Now, if anyone patient enough to read trough above CMakeLists.txt
files, I would be more than interested to hear is there anything that
could be improved.  I have also two additional questions:

1. Besides foo/lib and foo/src directories, I have foo/data and
foo/doc directories, with some data files and program man page
(foo/doc/bar.1) respectively.  How to structure CMakeLists.txt in
these directories in order to specify where to install these files
upon "make install"?

2. I'm accustomed to having some rules added to program Makefiles, for
example to have "beauty" target to call indent upon my C source code.
How to accomplish this?


Finally, I'd like to state that I really liked cmake so far.  It's too
early to make statements, but I guess that, if having no previous
experience with autotools, I'd need much more time to setup build
system for this simple project with autotools.  And what is even more
important, with cmake I understand most of the stuff; for example,
FindMPI.cmake is really simple and readable, while autoconf macros to
detect MPI with my autotools setup were black magic - I made
copy/paste of these from autoconf macro archive, but never understood
a bit of them...

Kind regards,
Crni


More information about the CMake mailing list