-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add ament package for pclint #98
Conversation
ament_pclint/ament_pclint/main.py
Outdated
|
||
|
||
def find_executable(file_name, additional_paths=None): | ||
if sys.platform == 'linux': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a small hack here because the binaries pclp64
is the Windows version, while linux and osx are distributed pclp64_linux
and pclp64_osx
.
ament_cmake_pclint/package.xml
Outdated
code using PCLint. | ||
</description> | ||
<maintainer email="jp.samper@apex.ai">Juan Pablo Samper</maintainer> | ||
<license>Apex.AI Proprietary License</license> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From this patch it is unclear what this license is. I think each package needs at least a LICENSE
file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dirk-thomas It will probably become Apache 2.0 (or another well-known license), I just copy-pasted the code for now, so you could start looking at the content.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Current the linter invocation fails when pclint
isn't available. That would prohibit it from being added as a "default" linter. I think it would be good to have it as a default linter in order to check for it when pclint
is available. Therefore I would suggest to gracefully skip linting when pclint
isn't available instead.
|
||
if(INCLUDED_DIRS) | ||
list(APPEND cmd "--include-directories" ${INCLUDED_DIRS}) | ||
set(_INCLUDE_DIRS_FLAG_SET "Found") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: indentation.
Same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
|
||
set(cmd "${ament_pclint_BIN}" ${ARG_UNPARSED_ARGUMENTS}) | ||
|
||
get_property(INCLUDED_DIRS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does it handle the case that no global include directories are being used but target specific include directories instead?
Same for compiler definitions below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% I understand the question, but I think what I meant to do here was gather all the directories included through cmake's include_directories
. The idea is that you need to tell pclint where to look for header files, not unlike how you have to tell cmake where to find header files.
It's likely that I'm misusing or misunderstanding something in cmake, though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, we want to give pclint compiler definitions added through target_compile_definitions, but again, I may be misunderstanding something fundamental about cmake.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CMake code might set these information on a per-targetg level using e.g. target_include_directories
and/or target_compile_definitions
. In that case the global variables might not be sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you're saying now. I was assuming that any headers are included with include_directories
What I'm thinking is we need to add PCLINT_INCLUDE_DIRS and PCLINT_COMPILE_DEFS options to ament_pclint
or do you know of something better to get information added via target_*()
?
Basically, pclint needs access to the exact same directories as the add_executable
or add_library
functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a better way then to let the user pass in the necessary flags manually. That can be either the include dirs directory or a list of targets from which the include dirs are being extracted.
Beside supporting these information as arguments in the CMake function the user also needs to be able to set some CMake variables for the case where the linter is being invoked implicitly by the ament_lint_auto
package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was considering how to do this as well. @jpsamper2009 is there not a way to retrieve all of the includes and flags for a particular target rather than the global scope in CMake?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what you want to do is:
get_target_property(TARGET_INC ${PROJECT_NAME} INCLUDE_DIRECTORIES)
message(STATUS "INCLUDES: " ${TARGET_INC})
get_target_property(TARGET_FLAGS ${PROJECT_NAME} COMPILE_FLAGS)
message(STATUS "FLAGS: " ${TARGET_FLAGS})
get_target_property(TARGET_DEF ${PROJECT_NAME} COMPILE_DEFINITIONS)
message(STATUS "DEFINITIONS: " ${TARGET_DEF})
And then use those generated variables to pass into pclint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Upon further reflection, I think that the appropriate way to handle ament_cmake_pclint
is to add a CMake function that takes a target as an argument. From there, we can retrieve the list of sources, includes, and compiler definitions/flags that are used on that target, to make the linting maximally effective.
This would also allow us to exclude things like unit tests, etc from pclint checking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mjcarroll I hadn't seen your comment above, so for now I've just added function arguments to allow the user to specify the include directories explicitly.
Do you guys have an example of a package with target-specific include directories and compiler flags?
endif() | ||
|
||
set(cmd ${cmd} PARENT_SCOPE) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: remove the empty lines right after function()
and before endfunction()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ament_cmake_pclint/package.xml
Outdated
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?> | ||
<package format="2"> | ||
<name>ament_cmake_pclint</name> | ||
<version>0.0.3</version> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The version should match the other packages in this repo which are currently 0.4.0.
Same in the other package as well as the setup.py
file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
ament_pclint/package.xml
Outdated
<maintainer email="jp.samper@apex.ai">Juan Pablo Samper</maintainer> | ||
<license>Apex.AI Proprietary License</license> | ||
|
||
<exec_depend>pclp64</exec_depend> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the release this needs to be a valid rosdep
key. If that is not feasible the dependency needs to be removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My guess is this won't be the case since it's a proprietary license, so I'll remove.
ament_pclint/ament_pclint/main.py
Outdated
', '.join(["'.%s'" % e for e in extensions])) | ||
parser.add_argument( | ||
'--language', | ||
help="Force pclint to analyze files as specified language. Supported languages c or cpp") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this provide a choices
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ament_pclint/ament_pclint/main.py
Outdated
if os.name == 'nt': | ||
parser.add_argument( | ||
'--pclint-config-dir', | ||
nargs=1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default value of nargs
is 1 so no need to specify it explicitly.
Same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ament_pclint/ament_pclint/main.py
Outdated
|
||
# Add include directories from arguments | ||
if args.include_directories is not None: | ||
for directory in args.include_directories: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion to avoid the extra conditional:
for directory in (args.include_directories or []):
Same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ament_pclint/ament_pclint/main.py
Outdated
# the number of cores cannot be determined, don't parallelize | ||
pass | ||
|
||
result = ['' for f in files] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: result = [''] * len(files)
Same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
ament_pclint/ament_pclint/main.py
Outdated
'--pclint-config-dir', | ||
nargs=1, | ||
type=str, | ||
default=[os.path.dirname(os.path.realpath(__file__)) + "/config/msvc"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use single quotes rather than double quotes where possible without escaping.
Same below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should probably be using os.path.join, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even better 👍
e5fefde
to
ebebe60
Compare
@dirk-thomas Do you have a suggestion on how to gracefully skip this test if pclint is not available? I'm thinking I can either check at the cmake level if the executable exists, and if it doesn't print a Warning and continue. I could also just do it at the ament_pclint.py level where if no executable is found, I print a warning and exit with return code 0. |
I would propose to set the For the command line tool I would rather return a non-zero error code when |
ebebe60
to
a05ad21
Compare
@mjcarroll Are you using this package? Do you have any feedback? |
@jpsamper2009 I have been using it (your internal version, I need to check against this one). My biggest things were the exit without the executable being found, and the handling of the compiler flags. I was also looking into retrieving the target flags for the open-source |
@mjcarroll @dirk-thomas I've reworked this a bit to get rid of some unused parts and address your suggestions. I'm afraid I didn't see #98 (comment) until just now, but maybe the current solution is sufficient to merge this, and we can work on reading information from a target on a separate issue? It would be good to get some people using it also to see what use cases we actually have instead of implementing a bunch of features that then go unused. |
We have to hold this anyway until we have moved to Ubuntu 18.04 since currently we only have CMake 3.5 available on 16.04 and this package require 3.9. |
What 3.9 features is this using? |
@mjcarroll The second commit is using the DISABLE property which is only available in 3.9 (#98 (comment)). As long as you have pclint installed, you should be able to use the first commit. @dirk-thomas Ack |
This has been moved back to in progress. Because we are going to try to keep some Xenial compatibility, we need to find a way to accomplish the |
(or just skip creating the test) |
e293644
to
5e5e6b1
Compare
@mjcarroll @dirk-thomas I have added a check to skip the test creation and print a warning if the executable is not found: (c3eaaf4) I have also put the CMake 3.9 solution into a different branch in case we want to go back to that version eventually: jpsamper2009@e293644 |
ament_pclint/setup.py
Outdated
author_email='jp.samper@apex.ai', | ||
maintainer='Juan Pablo Samper', | ||
maintainer_email='jp.samper@apex.ai', | ||
url='https://gitlab.com/ApexAI/ament_lint', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this point to this repo instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Fixed.
ament_pclint/setup.py
Outdated
long_description="""\ | ||
The ability to perform static code analysis on C/C++ code using PCLint | ||
and generate xUnit test result files.""", | ||
license='Apex AI', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This information doesn't match the package manifest which declares Apache 2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, too many places to change it :). Fixed now.
- Use config file with permissive license: http://www.gimpel.com/html/pub90/au-misra3.lnt
2f22615
to
7990ce5
Compare
I've just pushed a change to one of the pclint config files. The file is available online ( http://www.gimpel.com/html/pub90/au-misra3.lnt), but the version we were using had a less permissive license. I've instead adjusted the configuration linked above. |
@mjcarroll Please squash merge in the future. |
@dirk-thomas Sorry about that, I must have misclicked. |
FYI (unless you guys already fixed it) I finally found the option to check local headers we missed back then: Also, I use a forced check now for all headers even if they are not used by local sources (via creating throw-away trivial users). See below the relevant fragment from my # For each header file create a temp .cpp file that includes it via ""
# This way PCLint wil check all header files even for pure interface libraries
def prepare_source_files(source_files, include_files):
tempdir = tempfile.TemporaryDirectory(prefix='ament_pclintsa_')
for header_name in include_files:
if header_name.startswith('include/'):
# A hack which must be fixed
# remove "include/" prefix
header_name = header_name[8:]
header_name = header_name.replace('\\', '/')
src_name = os.path.join(tempdir.name, os.path.basename(header_name) + '.cpp')
with open(src_name, 'w') as f:
f.write('#include "' + header_name + '"\n')
source_files.append(src_name)
# return tempdir too so it will be deleted on the script's end
return source_files, tempdir |
@serge-nikulin This ticket has been closed for almost a year. The chances your comment will get lost is very high. Please either create a pull request with your proposed fragment or open an issue with the information (with a strong preference for the former). |
@wjwwood @mjcarroll @dejanpan
As promised, here is a copy of our
ament_pclint
andament_cmake_pclint
packages. I haven't made any changes yet (not even the licenses) because I figure it'll have to go through at least one round of review anyway.Neither of these will work if you don't have pclint plus installed (you can buy a license at http://www.gimpel.com)
The configuration files are modified versions of the ones found here: http://www.gimpel.com/html/ptch90.htm