我自己找到了解决问题的方法。在使用“NMake Makefiles”作为生成器时由 CMake 生成的文件中,每个目标都有一个名为“DependInfo.cmake”的文件。该文件位于每个目标的 CMakeFiles/.dir/DependInfo.cmake 中。在该文件中有一个名为“CMAKE_CXX_TARGET_INCLUDE_PATH”的变量,其中包含目标所需的所有包含路径。我最终做的是一个解析该文件的powershell脚本,然后在该变量中挑选出这些路径,并将它们输出到PC-Lint想要的格式的文件中。
Powershell脚本:
$projectRoot = $args[0]
$dependInfoFile = $args[1]
$output = $args[2]
if (Test-Path $dependInfoFile)
{
$lines = Get-Content $dependInfoFile
Remove-Item $output -Force -ErrorAction SilentlyContinue
foreach ($line in $lines)
{
if ($line -eq "set(CMAKE_CXX_TARGET_INCLUDE_PATH")
{
$printToFile = $TRUE
}
elseif ($printToFile -and ($line -eq " )"))
{
$printToFile = $FALSE
break
}
elseif ($printToFile)
{
$line = $line.trim()
$line = $line.Substring(1,$line.length-2)
while ($line.Substring(0,3) -eq "../")
{
$line = $line.SubString(3)
}
$outLine = "-i`"$projectRoot`/$line`""
Add-Content $output $outLine
}
}
}
对于 PC-lint,我添加了一个 custom_target,它使用正确的 DependInfo.cmake 文件和输出文件的名称运行这个 powershell 脚本。此 custom_target 作为对正常 lint 目标的依赖项添加,这导致在 lint 之前生成输出文件。(请注意,可能需要更改某些路径)
FindLint.cmake ( FindLint.cmake由 cmake 提供,但已修改)
# This file contains functions and configurations for generating PC-Lint build
# targets for your CMake projects.
set(PC_LINT_EXECUTABLE "c:/lint/lint-nt.exe" CACHE STRING "full path to the pc-lint executable. NOT the generated lin.bat")
set(PC_LINT_CONFIG_DIR "c:/lint/" CACHE STRING "full path to the directory containing pc-lint configuration files")
set(PC_LINT_USER_FLAGS "-b" CACHE STRING "additional pc-lint command line options -- some flags of pc-lint cannot be set in option files (most notably -b)")
# a phony target which causes all available *_LINT targets to be executed
add_custom_target(ALL_LINT)
# add_pc_lint(target source1 [source2 ...])
#
# Takes a list of source files and generates a build target which can be used
# for linting all files
#
# The generated lint commands assume that a top-level config file named
# 'std.lnt' resides in the configuration directory 'PC_LINT_CONFIG_DIR'. This
# config file must include all other config files. This is standard lint
# behaviour.
#
# Parameters:
# - target: the name of the target to which the sources belong. You will get a
# new build target named ${target}_LINT
# - source1 ... : a list of source files to be linted. Just pass the same list
# as you passed for add_executable or add_library. Everything except
# C and CPP files (*.c, *.cpp, *.cxx) will be filtered out.
#
# Example:
# If you have a CMakeLists.txt which generates an executable like this:
#
# set(MAIN_SOURCES main.c foo.c bar.c)
# add_executable(main ${MAIN_SOURCES})
#
# include this file
#
# include(/path/to/pc_lint.cmake)
#
# and add a line to generate the main_LINT target
#
# if(COMMAND add_pc_lint)
# add_pc_lint(main ${MAIN_SOURCES})
# endif(COMMAND add_pc_lint)
#
function(add_pc_lint target)
get_directory_property(lint_include_directories INCLUDE_DIRECTORIES)
get_directory_property(lint_defines COMPILE_DEFINITIONS)
# let's get those elephants across the alps
# prepend each include directory with "-i"; also quotes the directory
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/lint_include/${target}.lnt "")
foreach(include_dir ${lint_include_directories})
file(APPEND ${CMAKE_CURRENT_BINARY_DIR}/lint_include/${target}.lnt -i"${include_dir}"\n)
endforeach(include_dir)
# prepend each definition with "-d"
set(lint_defines_transformed)
foreach(definition ${lint_defines})
list(APPEND lint_defines_transformed -d${definition})
endforeach(definition)
# list of all commands, one for each given source file
set(pc_lint_commands)
foreach(sourcefile ${ARGN})
# only include c and cpp files
if( sourcefile MATCHES \\.c$|\\.cxx$|\\.cpp$ )
# make filename absolute
get_filename_component(sourcefile_abs ${sourcefile} ABSOLUTE)
# create command line for linting one source file and add it to the list of commands
list(APPEND pc_lint_commands
COMMAND ${PC_LINT_EXECUTABLE}
-i"${PC_LINT_CONFIG_DIR}" std.lnt
"-u" ${PC_LINT_USER_FLAGS}
"${CMAKE_CURRENT_BINARY_DIR}/lint_include/${target}.lnt"
${lint_defines_transformed}
${sourcefile_abs})
endif()
endforeach(sourcefile)
add_custom_target(${target}_LINT_INCLUDE
powershell.exe -File \"${CMAKE_MODULE_PATH}/generate_lint_include.ps1\" ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${target}.dir/DependInfo.cmake ${CMAKE_CURRENT_BINARY_DIR}/lint_include/${target}.lnt)
# add a custom target consisting of all the commands generated above
add_custom_target(${target}_LINT ${pc_lint_commands} VERBATIM)
add_dependencies(${target}_LINT ${target}_LINT_INCLUDE)
# make the ALL_LINT target depend on each and every *_LINT target
add_dependencies(lint ${target}_LINT)
endfunction(add_pc_lint)