Skip to content

Progress on gcc plugins

Saturday, 9 May 2009  |  brad hards

In a previous blog entry, I discussed some initial work on GCC plugins. Since then, the GCC gurus (in particular, Rafael Avila de Espindola) have made sure headers get installed correctly.

I was a bit confused about how you can find the header location (since it isn't part of the normal header paths), but David Korn pointed out the -print-file-name= command line option for gcc. If you ask for -print-file-name=plugin/include/, then this could be a good path. Turns out if you get back plugin/include/, then gcc can't find the file name / path.

So I stretched my cmake skillz, and came up with this:

- Find GCCPlugins

Find the include path for GCC plugin headers

This module defines

GCCPLUGINS_FOUND - whether the GCC Plugin support was found

GCCPLUGINS_INCLUDE_DIR - the include path for GCC plugin headers

if (GCCPLUGINS_INCLUDE_DIR)

Already in cache

set (GCCPLUGINS_FOUND TRUE)

else (GCCPLUGINS_INCLUDE_DIR)

Ask the compiler where to find the paths

IF(NOT CMAKE_COMPILER_IS_GNUCC) SET(GCCPLUGINS_FOUND FALSE) RETURN() ENDIF(NOT CMAKE_COMPILER_IS_GNUCC)

EXECUTE_PROCESS( COMMAND ${CMAKE_C_COMPILER} "-print-file-name=plugin/include/" OUTPUT_VARIABLE _gccplugins_path ERROR_VARIABLE _gccplugins_error )

IF(_gccplugins_error) # perhaps not really gcc SET(GCCPLUGINS_FOUND FALSE) RETURN() ENDIF(_gccplugins_error)

STRING( REGEX REPLACE "[\n]" "" _gccplugins_path "${_gccplugins_path}" ) IF(_gccplugins_path STREQUAL "plugin/include/") # we don't have this path - it needs some suffix SET(GCCPLUGINS_FOUND FALSE) RETURN() ENDIF(_gccplugins_path STREQUAL "plugin/include/")

OK, so it looks like we have a real plugin path. Check the headers are there

FIND_PATH(GCCPLUGINS_INCLUDE_DIR NAMES gcc-plugin.h PATHS ${_gccplugins_path} NO_DEFAULT_PATHS DOC "GCC plugins include path")

IF(GCCPLUGINS_INCLUDE_DIR) SET(GCCPLUGINS_FOUND TRUE) ELSE(GCCPLUGINS_INCLUDE_DIR) SET(GCCPLUGINS_FOUND FALSE) ENDIF(GCCPLUGINS_INCLUDE_DIR)

endif (GCCPLUGINS_INCLUDE_DIR)

(The STRING( REGEX REPLACE ) had me going for a while. I couldn't figure out why the FIND_PATH didn't work - turns out there is a newline at the end of the _gccplugins_path and that stops the FIND_PATH.)

Then the CMakeLists.txt can just become project( MyGccPlugin )

Probably nothing that needs 2.6, but that is what I tested with

cmake_minimum_required(VERSION 2.6)

Find the GCC plugin headers

set( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ) find_package( GCCPlugins REQUIRED ) include_directories( ${GCCPLUGINS_INCLUDE_DIR} )

Source files for the plugin

set( my_gcc_plugin_SRCS my_gcc_plugin.c )

build the plugin (share library object)

add_library( my_gcc_plugin MODULE ${my_gcc_plugin_SRCS} )

have the name set to my_gcc_plugin.so (on Linux) rather than

libmy_gcc_plugin.so

set_target_properties( my_gcc_plugin PROPERTIES PREFIX "" )

(Dear lazyweb: why doesn't find_package( GCCPlugins REQUIRED ) cause the cmake run to fail if the headers aren't found?)

Anyway, enough about buildsystem.

The plugin I've been experimenting with is to check the system call. I currently have code that checks each function call, and can produce a warning if the name of the function call is system. However that will produce a lot of false positives. Consider a function that looks like: void bar(char * variable) { const char* const appname = "df";

system("ls");
system(variable);
system(appname);

}

It isn't too hard to eliminate the first case (where the first argument is a constant expression), which is an improvement over just using grep or ack. What I'm aiming to do is to warn on only the second case (where the argument really isn't const) and not on the third case. To do that, I need to keep track of the arguments, and that might involve understanding how gcc tracks aliasing.