PointCloudLibrary / pcl

Point Cloud Library (PCL)
https://pointclouds.org/
Other
9.83k stars 4.6k forks source link

Alternative way to structure the code files #3837

Open SunBlack opened 4 years ago

SunBlack commented 4 years ago

Every time I check automatic code changes by clang tidy I have the feeling the code structure of PCL has more disadvantages than benefits:

Current file structure

File structure

pcl/<module>/include/pcl/<module>/impl/<file>.hpp
pcl/<module>/include/pcl/<module>/<file>.h
pcl/<module>/src/<file>.cpp

CMake structure

set(srcs
  src/<file>.cpp
)

set(incs
  "include/pcl/${SUBSYS_NAME}/<file>.h"
)

set(impl_incs
  "include/pcl/${SUBSYS_NAME}/impl/<file>.hpp"
)

Advantages:

Disadvantages

Example where you can see it

Local git tool: image

GitHub: image

Alternatively file structure

File structure

pcl/<module>/<file>.cpp
pcl/<module>/<file>.h
pcl/<module>/<file>.hpp

CMake structure

set(srcs
  <file>.cpp
  <file>.h
  <file>.hpp
)

Advantages:

(Dis)advantages

Last file structure is e.g. used by Qt as fast I saw until now. We have a similar code structure in our project and it is really always a pain in the ass to switch between files or review sth. here ;-)

Hint: In case you agree I would see it as long term issue, as we should then discuss when to apply this changes, as a lot of PRs will get broken (expect Git & Github manages to follow renaming of files as we don't need to touch source files)

0sidharth commented 4 years ago

I believe this produces issues with #pragma once and would require a change back to #ifndef include header guards, going against #3774 . But maybe wait for a maintainer comment.

SunBlack commented 4 years ago

Why it should produce issues with #pragma once?

0sidharth commented 4 years ago

On a closer look, I don't think there'll be an issue. My concern was that #pragma once ignores different files in different locations if they gave the same name. I don't think that will arise here, so #pragma once shouldn't be an issue.

kunaltyagi commented 4 years ago

We need a migration path for any breaking change. If we can prevent any breaking change via CMake, it might be easier.

Regarding the organization of files, I've seen a lot of usage of the following layout:

Sticking everything together would have its own drawbacks, such as a huge number of files in one folder (thrice in worst case), which might prompt another PR in future: "separate files because it's difficult to find the correct one"

SergioRAgostinho commented 4 years ago

I'm a little with @kunaltyagi on this one. I don't believe there's an optimal way of addressing this organization, otherwise we would have seen something coming out of the CppGuidelines and everyone on the cpp community would be preaching about it. Ultimately is a matter of preference and every approach will have strong points and drawbacks. I'm ok with the current organization and really only have issues with some modules (cough gpu) which don't adhere to it properly.

kunaltyagi commented 4 years ago

You need to take care of cold and coughs in this weather @SergioRAgostinho

I'll be fine with an explicit difference between API and implementation detail (and in fact, that'll help us in the long run with deprecation) (even if we start with or touch only the offending modules)

Now for the controversial part: I believe it might be better to undertake this effort with an eye on Modules (not supporting modules, just making sure we don't do the reorg twice)

taketwo commented 4 years ago

You missed one more advantage of the current structure. In fact, it's probably the raison d'être of it! The apparent redundancy in the paths:

pcl/<module>/include/pcl/<module>/<file>.h

where the library name and the module name are repeated twice is needed to make sure that the same include paths (pcl/<module>/<file>.h) are valid both in build tree and when distributed.

As @SergioRAgostinho wrote, there is no golden standard of organizing C++ libraries. There are different approaches with their own pros and cons. In such situations, I strongly prefer to keep the status quo.

SunBlack commented 4 years ago

Just coming back to this, as I saw a lot of more code of the PCl during applying .clang-format ;-)

You missed one more advantage of the current structure. In fact, it's probably the raison d'être of it! The apparent redundancy in the paths:

pcl/<module>/include/pcl/<module>/<file>.h

where the library name and the module name are repeated twice is needed to make sure that the same include paths (pcl/<module>/<file>.h) are valid both in build tree and when distributed.

There is no difference between both approaches, as we move only the cpp & hpp files into the header directories and remove unnecessary directories. So fully structure would look like this:

apps/<app>/...
pcl/<module>/<file>.cpp
pcl/<module>/<file>.h
pcl/<module>/<file>.hpp
tests/<module>/...
CMakeLists.txt

Okay, that is the only really disadvantage: You don't have the module in root directory, instead you have a pcl directory (like Boost it is handling in its installed version).

In general PCL doesn't really completely follow even the current rule: pcl/<module>/include/pcl/<module>/<file>.h. Example: compression is part of io but included like they are separate modules (#include <pcl/compression/color_coding.h). In gpu a lot of includes are via #include "..." to include headers which lays aside of the current header or in simulation/tools you don't have even a proper include_directories defined, so we can't exchange #include "..." without much effort. What I want to say with it: Even the current structure does not prevent the #includes from being revived manually in a PR. The only thing: You prevent now to include header files from cpp via #include ""

As @SergioRAgostinho wrote, there is no golden standard of organizing C++ libraries. There are different approaches with their own pros and cons. In such situations, I strongly prefer to keep the status quo.

I agree that there is no golden standard (e.g. where to locate gpu submodules, tests, ...). But currently I ask myself why the PCl seems the only bigger project with this architecture. LLVM, Mozilla, Google, Qt... - all have the source at the side of the header.

Why I'm currently discussing this? I'm currently think about restructure some bad directories. E.g. in apps you have no idea which files belong together, as only a few apps are separated into different directories.

We have currently following issues with folder structure (only a fast check):

As you can see: Maybe half of the modules may be okay currently (✔️), some should be restructured slightly (❓) (mostly move tools out of the module), there are still some modules (❌) which should be restructured to follow current rules. And before we start it, how we this result be to prevent unnecessary move commits.

In general imho:

kunaltyagi commented 4 years ago

It makes sense to split tools (just like examples) separate from pcl_libs (other modules) and organize it (I think there was some work underway for that). It can be done either

SunBlack commented 4 years ago
  • Maybe just have tools and examples. Tools will have certain standard while examples will have more leeway (eg: no proper cmdline interface, less flexible, more hardcoded values, etc.)

Agree, but it will be hard to decide in some cases, as some tools are really short, so you don't know is this an example or or a tool. See e.g. this. Maybe it is enough to have apps and the example within the documentation and remove all other old examples.

It makes sense to split tools (just like examples) separate from pcl_libs (other modules) and organize it (I think there was some work underway for that). It can be done either

  • similar to pcl/ (aka tools/<module>/<tool_name>): helps in discovery
  • flat (aka tools/<tool_name>): discovery via README or something else. Flatter structure, less worry about what module tool is intended for

As some tools may use multiple modules tools/<module>/<tool_name> makes no sense, or you wan't e.g. tools/io_kdtree/<tool_name>? ;-)

kunaltyagi commented 4 years ago

The name itself of the example you provided has example in it, so I'd say in reorg, it'll go to examples. And yeah, flat makes more sense for tools

SergioRAgostinho commented 4 years ago

Just adding some more info for decision making. I believe the distinction between tools and apps was the gui. Apps are meant to be standalone gui enabled executables. Tool are supposed to be command line oriented executables.

It's not necessarily a happy division because semantically speaking point_cloud_editor is definitely a work tool.

Nevertheless, setting this distinction might help organize thoughts.

SunBlack commented 4 years ago

Just adding some more info for decision making. I believe the distinction between tools and apps was the gui. Apps are mean to be standalone gui enabled executables. Tool are supposed to be command line oriented executables.

So maybe this be reflected in the path, e.g. tools_gui and tools_cui (sound ugly, but... 😆)

kunaltyagi commented 4 years ago

Keeping GUI and CLI separate makes sense only since GUI has dependency on visualization libraries (either pcl_visualization or some other library too). No strong reason (if I'm not building visualization, I don't need to build tools_gui, just tools_cli to borrow the terms) since this can be managed by CMake.

Options:

kunaltyagi commented 4 years ago

@sunblack Could you please revive this thread by stating the conclusions made and the points left to discuss?

SergioRAgostinho commented 4 years ago

Keeping GUI and CLI separate makes sense only since GUI has dependency on visualization libraries (either pcl_visualization or some other library too).

I believe some of our CL tools breach this assumption as well. They are command line in the sense that you literally need to supply proper arguments so that they run, but some of them also open visualization windows.

This was also one of the issues with some of the tools for Mac. In order the properly parse mouse click events, the executables had to be converted to app bundles, but then you could no longer supply proper input arguments (at least not without some effort) because now the user sees an application bundle and double clicks to execute it (like any other app bundle on macOS).

kunaltyagi commented 4 years ago

This was also one of the issues with some of the tools for Mac

(#refactor, unrelated) Maybe we should have 2 binaries:

If so, it'd make less sense to keep gui and cli in separate modules since they are "dependent" on each other