Git Product home page Git Product logo

pitchfork's Introduction

Pitchfork

Pitchfork is a set of conventions for native C and C++ projects. The most prominent being the project layout conventions.

The layout specification document is available in data/spec.bs.

Why the Name Pitchfork?

The very first public unveiling, drafting, and discussion of these project conventions started with a Reddit thread entitled "Prepare thy Pitchforks". Until that point, I had not chosen any particular name for the conventions, but I felt "Pitchfork" was as apt a name as any.

The pf Tool

This repository also hosts a (currently experimental) tool that helps you create and work with Pitchfork-compliant projects.

This project is still very young and has a while to go before being a useful developer tool. Once ready, this README will be updated with proper user documentation.

The pf Library

The pf tool mentioned above is built upon the pf library, also hosted in this repository. This library can be used to query and manipulate Pitchfork-compliant projects.

pitchfork's People

Contributors

quincunx271 avatar vector-of-bool avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pitchfork's Issues

Directory naming inconsistency

Hi,
I really appreciate the work, time and effort you put into PFL.
I was just starting a new C/C++ project and was wondering what are the current best practices for organizing files. So I was looking into it when I found your research, proposed layout.
I read through The Pitchfork Layout (PFL) ideas, reddit post and Project Layout Survey Results and Updates.

I understand this to be the most popular, status-quo, currently established (but not necessarily best) practices.

I had some thoughts that wouldn’t let me rest, to not say something in good conscious.
So if you let me I’d like to share some constructive criticism:
Project Directory naming seems really inconsistent.

I understand that names came out as most popular vote in individual poll questions, and that might be the cause of inconsistency. The other reason is “We are already used to it” [this mess].

I have problem along 2 axes with lack of consistency: plurality and abbreviation.

  • Singular

    • build/
    • src/
    • include/
    • external/
  • Plural

    • tests/
    • examples/
    • extras/
    • data/
    • tools/
    • docs/
    • libs/
  • Abbreviated

    • src/
    • docs/
    • libs/
  • Not abbreviated

    • build/
    • include/
    • tests/
    • examples/
    • external/
    • extras/
    • data/
    • tools/

Does this project only have one source but multiple docs, libs?

Please, this cannot be the proposed layout for new designs. (That we will have to live with for decades.)

There are others like source - header, compile - include pairs yet the proposal suggests using src (source) with include… but I’m gonna let linguists deal with that one…

I would be interested in a new poll voting between 4 consistent naming scheme, and another vote between the winner and the current inconsistent PFL (or a vote between the 5 – not sure if forcing people who would want the current layout to choose their least offending consistent layout would be beneficial or not - would need to ask a survey specialist for their opinion).

Singular Not abbreviated

Plural Not abbreviated

  • sources/
  • documentations/
  • libraries/
  • builds/
  • includes/
  • tests/
  • examples/
  • externals/
  • extras/ * or optionals/, see later
  • data/ * It has Schrödinger’s plurality, it’s both or just don’t ask before it collapses ;)
  • tools/

Singular Abbreviated

  • src/
  • doc/
  • lib/
  • bld/ * would bil/ be better?
  • inc/
  • tst/ * tes/? or are we good with test/ and it’s a 4 character limit
  • exa/ * xmp/? or exam/
  • ext/
  • opt/ * here is where optional/ comes in instead of extra/
  • dat/ *
  • too/ * tol/? tl/? or keep 4 character tool/ here too?

Plural Abbreviated

  • srcs/
  • docs/
  • libs/
  • blds/ * would bils/ be better?
  • incs/
  • tsts/ * tess/? or tests/
  • exas/ * xmps/? or exams/
  • exts/
  • opts/ * here is where optionals/ comes in instead of extras/
  • data/ * or you can even have dats/
  • toos/ * tols/? tls/? or keep tools/

I think both SNA, PNA would be acceptable. I don’t think anyone would like full SA, PA.

I can live with if people are married to src and they don’t want to type a few extra characters because it’s so common but I do think it’s stupid. (I mean it’s stupid that they don’t want to change it because they are so used to it. Or that they have to type src and a tool doesn’t auto-completes it to source. Well, people were also used to slavery but over time they realized that it’s not right.. this is certainly less important, we’ll see if it gets into history books – “How security flaws in C codes ended the world” is more likely)
I’m also fine with lib abbreviation, but libs just don’t make any sense to me. It should be either srcs, libs, docs or src, lib, doc trio.

In the poll there were no singular lib option (only libs, mods, and subdiv ...ew yuck), so I don’t know statistically how sound are these results. (plugins, modules were also not an option? also mods just sound to me like twitch moderators now, and libs like political liberals) That poll looks like a prime candidate for redoing. (But it doesn’t really matter to me, I’m not involved in large scale software development, I’m usually doing embedded firmware development. To me lib sounds like a folder containing any libraries used - internal or external, or maybe compiled library files that the project publishes for other project to use. So I’m clearly out of my depth here. Though to me it sounds a bit confusing. Modules, parts, components might sounds more intuitive IMO than lib, but people who work on these daily probably have better ideas.)

I don’t like using both external and extras names because they sound so similar (or abbreviate to the same 3 letter).
Just to be clear:

  • external/ is any external dependency (which can something you wget or git submodules...)
  • extras/ is a submodule root (but not git submodule, because that goes into external) (and it’s the optional submodules, not the mandatory ones)
  • and libs/ is where the mandatory submodules are ...if the project is divided into submodules (but again not git submodules, because that’s different)

Can anyone else besides me see why this terminology could be confusing?
I understand that you didn’t want to shoot yourself in the foot by calling them modules or packages because that would be confusing… so you shot your other leg instead ;)

I don’t know if component(s) would do or if that also used for describing something else.
As alternative I would suggest sub-project (instead of submodule which can describe another external dependencies aka projects). We are describing project layouts, if a project is divided into smaller parts/projects those could rightly be called sub-projects, no?

I think calling it package would be less confusing than submodule but not right.
Calling them modules is not great either but is submodule any better? If it’s a submodule what’s a module? Oh right a completely different thing a C++ module. Does that make any sense?
Do C++ modules go into module(s) directory? No? Why?
If we are not using modules directory (to publish C++ modules) then we could use it to hold sub-projects/project parts/project-modules (in contrast to C++ modules) … but shouldn’t!

Looking at the proposed submodule directory structure, these seem like full blown projects (with a common build/ system, external/ dependencies and tools/ ), they aren’t even really sub-projects. (But they are strongly coupled, maybe depend on each other… so they go into the same repo.)
So it’s a repository with many projects. No? Why aren’t we calling these submodules just projects?
Maybe our problem is that we are describing PFL as a project layout, when we should be describing it as a repository layout.
If a repository contains many projects, then why aren’t we calling it … just a repository. We can call it a many-project repository to differentiate it from a single project repository… or we can just borrow Visual Studio’s terminology and call it a “solution”. A solution contains one or more than one projects. Is this not what we are talking about here?
Will repositories hold more than one PFL Projects? Clearly a project can depend on other git submodules.
By the way thanks git for calling them submodules and not subrepos!
So PFL describes a repository and its subrepo dependencies, right? (And those dependencies should also follow PFL)
So PFL should apply to the whole repository, or can multiple PFL live in sub-directories of a repository?
Depending on that we can call PFL a repository layout instead of project layout, or call it a solution layout (which can have many inter dependent projects).
Am I right that a (multi VS project) VS solution can be a PFL project where the solution’s projects live in the submodule root directory but the solution cannot be PFL submodule … doesn’t seem like the directory structures would work out. Or can PFL submodules be nested and divided further?

Anyway, I think external/ directory name is fine for dependencies (I know deps is not good, so neither is dep, maybe req/ could be an alternative as in requirements, required dependencies), but for multi project solutions libs and extras doesn’t seem great. External and extras sounds more closly related than libs and extras. Wouldn’t required/ and optional/ be better? Should they even be top level directories or 2 sub-directories of modules or projects or parts or whatever (maybe it’s a solution name, maybe it stays libs or lib I don’t know).

Well I hope that some of this helps someone somewhere at some point.

TLDR:
I think this is the most abbreviated I would ever go for

  • src/
  • doc/
  • lib/
  • build/
  • inc/
  • test/
  • example/
  • ext/
  • opt/
  • dat/
  • tool/

And any build system that worth its weight in salt should handle the optional plural s ending(s)
and any mix between these abbreviations and full non abbreviated folder/directory names:

  • source/
  • documentation/
  • library/ (I would rename/move this if its purpose is to hold many inter related projects)
  • build/
  • include/
  • test/
  • example/
  • external/
  • optional/
  • data/
  • tool/

Because until we can agree on a consistent naming method people will mix and match to their heart desire.

Cloneable templates.

I love the effort put together on this project. However, I feel like there currently is an unnecessary level of friction making a project like this. I get that the "pf" tool should help with this. But since that is not complete yet I would love to have a few sub directories (maybe other repo's?) I could clone which contain the layout. More specifically, with various build systems in place.

Reason being that making visual studio project is a bit of a hassle, you need to move the *.vxproj. then change all the include, build and output settings.

I am currently also looking into making a VS project template, which may be a good fit for that particular IDE.

404 for "this version" url

This url doesn't seem to exist:

URL: https://vector-of-bool.github.io/psl.html

Not sure where it should point though, I don't understand how the spec.bs stuff works. I thought maybe /pfl.html (f rather than s) but that's not it. You're 404 page is awesome btw xD

Feedback on spec

I assume that this repository is related to this specification; I couldn't otherwise find anywhere appropriate to give feedback after reading that.

  1. The link at the top of the page to the specification itself is broken.
  2. Why is it that submodules are forbidden from containing further submodules? While directory depth can be a concern, it seems like a bad idea to restrict this.
  3. When using Separate Header Placement, is cat/sounds/meow.cpp expected to #include <cat/sounds/meow.hpp> or #include "../../../include/cat/sounds/meow.hpp"?
  4. In Source Directory Layout, does this imply that a library should always declare symbols in a non-global namespace (and thus in Separate Header Placement there would never be any files in the top-level include or src directories)?
  5. What is the reason for suggesting that tests could be implemented in the src directory? Doesn't this conflict with the idea that the library should not build its tests when consumed from another library?
  6. Generated files are explicitly forbidden from being in include or src. Where then do they go? How is this reconciled when generated files need to be compiled or included by library consumers? What if the library consumer is not expected to be able to run the tool which generates the file?

Question about playing nice with IDEs

After some escapades with getting eclipse to behave nice, while not complicating a simple use-as-subdirectory I ended up with

src
    include
    CMakelist.txt (1)
test
    CMakelist.txt (2)
CMakelist.txt (3)

This would allow depended projects just pointing to (1) as subdirectory, or users just using this subdirectory to get to the lib/public includes quickly.
Tests (2) could be similarly standalone, using the installed system libraries instead of the sources.

While (3) is primarily for aiding development and easy integration into IDEs (fitting defaults, incl unit tests).

I started with a similar layout like pitchfork, placing include at the root, but I got somewhat biased against that, as in practice header + sources are tied closer to each other than the remaining categories. for ex:

  • common git subtree for history
  • generating a public config.h fits more into the src directory (needs information from the build), but is semantically a installable include
  • they are typically installed together, so that should be done in one buildscriptfile (that I dont want in the root directory)

Extraneous move-from-local in return statements

Clang caught some unneeded std::moves which inhibit copy elision:

fs.hpp line 39

inline std::fstream open(const fs::path& filepath, std::ios::openmode mode) {
    std::error_code ec;
    auto            ret = open(filepath, mode, ec);
    if (ec) {
        throw std::system_error{ec, "Open file: " + filepath.string()};
    }
    return std::move(ret); // error: moving a local object in a return statement prevents copy elision [-Werror,-Wpessimizing-move]
}

fs.cpp line 13

std::fstream pf::open(const fs::path& filepath, std::ios::openmode mode, std::error_code& ec) {
    std::fstream ret;
    auto         mask = ret.exceptions() | std::ios::failbit;
    ret.exceptions(mask);

    try {
        ret.open(filepath.string(), mode);
    } catch (const std::ios::failure& e) {
        ec = e.code();
    }
    return std::move(ret); // error: moving a local object in a return statement prevents copy elision [-Werror,-Wpessimizing-move]
}

In both these cases, the return std::move(ret); should simply be return ret;

feedback

Hello,
So I just tested pitchfork for the first time. Here is the remarks I have after running pf new

Tests:

  • I would have loved that a menu proposed me to directly use a testing framework (e.g. Catch2, or gtest), and creates a test using this framework.

Build

  • I try to build the project immediately, and cmake complained because the folder third_party and tests don't contains a CMakeList.txt file. If pf could generates unit test, it would contains the corresponding CMakeList.txt file. For the third-party folder, I don't know if add_subdirectory can generate a warning (or if it could test if third_party/CMakeList.txt exists before doing add_directory)?

Doc

  • I think pf shoud ask if you want to create a doc folder. An empty doc folder will not help anyone ;)

Basic files

  • I think that pf should create a Readme.md in the main directory.
  • Likewise, it should ask witch license you want (with a list of popular licenses) and create the appropriate LICENCE.txt file.

Help

  • pf --help should give a bit more help, or redirect to a more complete webpage. For example I think it should explain how to add an external dependency, or how to create an internal library.

Additional tooling

  • pf could help setting-up good practice by adding a .clang-format file, and maybe other tools (like code coverage, version control, …). Feature creep could be a limitation, especially if you want to give choices in the implementation of said tools, but I think it's an option to evaluate.

I know that pf is still an early work in progress, and I must admit that I think you had an awesome idea when you created it.

No src directory in merged header placement mode?

Thanks for creating PFL! The merged header placement rules seem to overlap quite well with build2's canonical project layout. However, I notice two differences, in build2:

  1. the src project is omitted and the name of the project is used directly (skips one level of nesting).
  2. The tests directory is only for functional/integration tests since tests are placed next to headers/sources in the merged mode.

Any thoughts on these?

Configure fails on windows at zlib2 step

Hello,

I would like to evaluate pitchfork tool. Unfortunately, I can't configure it.

I use cmake 3.14.4 and conan 1.11.1

The configure step fails at zlib. When inspecting my folders, I see a file C:\\Users\\MartyLake\\.conan\\data\\zlib\\1.2.11\\conan\\stable\\package\\46fecbf5b55c9a04d9e1ce376246b1f9e619c3b7.dirty of size 0 instead of (I suppose?) a folder that would contain the zlib lib.

Here is the end of cmake log:

zlib/1.2.11@conan/stable: 
Calling package()

ERROR: zlib/1.2.11@conan/stable: Error in package() method, line 185
	self._rename_libraries()
while calling '_rename_libraries', line 133
	os.rename(current_lib, os.path.join(lib_path, "zlib.lib"))
	FileNotFoundError: [WinError 2] Le fichier spécifié est introuvable: 'C:\\Users\\MartyLake\\.conan\\data\\zlib\\1.2.11\\conan\\stable\\package\\46fecbf5b55c9a04d9e1ce376246b1f9e619c3b7\\lib\\zlibstatic.lib' -> 'C:\\Users\\MartyLake\\.conan\\data\\zlib\\1.2.11\\conan\\stable\\package\\46fecbf5b55c9a04d9e1ce376246b1f9e619c3b7\\lib\\zlib.lib'

CMake Error at build/_pmm/1.3.1/conan.cmake:470 (message):
  Conan install failed [1]:

Call Stack (most recent call first):
  build/_pmm/1.3.1/conan.cmake:495 (_pmm_conan_install_1)
  build/_pmm/1.3.1/conan.cmake:643 (_pmm_conan_install)
  build/_pmm/1.3.1/main.cmake:32 (_pmm_conan)
  build/_pmm/1.3.1/main.cmake:47 (_pmm_project_fn)
  CMakeLists.txt:32 (pmm)


CMake Error at build/_pmm/1.3.1/conan.cmake:500 (message):
  Conan dependencies were not imported (Expected file
  C:/Users/MartyLake/Dev/pitchfork/build/conanbuildinfo.cmake).  You may need to
  run Conan manually (from the build directory).  Ensure you are using the
  'cmake' generator.
Call Stack (most recent call first):
  build/_pmm/1.3.1/conan.cmake:643 (_pmm_conan_install)
  build/_pmm/1.3.1/main.cmake:32 (_pmm_conan)
  build/_pmm/1.3.1/main.cmake:47 (_pmm_project_fn)
  CMakeLists.txt:32 (pmm)


CMake Error at CMakeLists.txt:33 (conan_set_find_paths):
  Unknown CMake command "conan_set_find_paths".

How to set include directories in CMake

Assume a layout like this:

- src 
  - namespace
    - foo.cpp
    - foo2.cpp
- include
  - namespace
    - foo.hpp
- test 
  - namespace
    - foo.cpp

Where shall CMakeLists.txt files go? I would assume 1 in root and 1 in test.

This would mean the library itself is added in the top-level cmake with: add_library(foo src/namespace/foo.cpp src/namespace/foo2.cpp)

The redundancy is kinda annoying especially with deeply nested namespaces. So one could put 1 into the lowest, common namespace which compacts this to add_library(foo foo.cpp foo2.cpp)

Much better, but what now with target_include_directories? Put it again into top-level CMakeLists? Use ${PROJECT_SOURCE_DIR}/include? The former is disallowed by CMake (IIRC) and the latter fails for submodules (src/include in a subfolder for libs).

One could use ../../include but that relative path bugs me as a red flag.

Any suggestions?

PS: Why is no mention of CMake in the spec document?

Submodules

First; fantastic job on putting this together.

Now my problem; the concept of submodules.
I'll try to make it short;
Lumping everything together in the same src/ directory is not ideal from an "isolation" standpoint. We are very careful with the interfaces between our components, making only that which is necessary public -- and then we ignore this concept completely on the physical level.

I have a project with separate "modules" even for smaller parts and was considering putting them together in the same src/ directory and join their CMakeLists.txt into the top one -- but that means those modules will be permanently "fused" and you loose an important point of separation.

I think John Lakos original idea regarding "packages" may be more what I want here, but I have not read his book yet (been waiting for the new one for a while ...)

Thoughts?

No tests were found!!!

Even though the enable_testing() function is getting called by pf_auto(...), CTest cannot find any tests.

Adding the enable_testing() call before the call to pf_auto() works, though. Adding the enable_testing() call after the call to pf_auto() does not work. This looks like a CMake bug, either in source or in documentation. It looks like the call to enable_testing() must appear before any tests are defined

To reproduce this, make sure you start with a fresh build directory.

Where to put external libraries?

I find the PFL very appealing and would like to use this layout in my future C++ projects, also because the documentation is easily forwardeable and reasonable.

In the Introduction it is mentioned that external libraries, but I could not find an explanation regarding them in the rest of the document.
Should they be put into /external because it is "embedding an external project"?
However in the next line it is stated that "external/ should not contain files other than those required by tooling.", which made me doubt where to put a "libxxx.so" I link against in my project.
Is linking against a shared lib also considered tooling? Could this be clarified, or stated more clearly?

Feedback on cxx-pflR1 (2018-11-14)

Hello,

I'm pretty late to the party and stumbled across Pitchfork two days ago. I'm very interested in the future of the C++ ecosystem (build/tool integration as well as modernization/modern usage of the C++ language itself). I do think a common filesystem for C++ (and C) source code would be great. So, thanks for you effort!

I've been using a (self-created) CMake-based Convention over Configuration (CoC) for some time now and I think I'm pretty good and confident using CMake and a component-centric approach using a small-to-medium scale code base. I.e. I know what works in general and what not. My framework is almost zero-conf, except dependency management: dependencies are listed in CMakeLists.txt, but find_package calls are propagated transitively to downstream projects by the system. Using a package manager is not possible yet.

Suprisingly (or not) I'm already using the same concepts (library-centric, one library per project, distinction between "app" and "lib" projects, etc.) and file system layout as defined in the PFL (with some minor modifications).

I'm using this issue to provide some feedback to you. Please tell me if I can help with anything else (though my time is pretty limited).

  • Question: Where do we store Interface Definition Language (IDL), e.g. Protobuf or CORBA? They are code, imo. Therefore data does not fit. Since now I've been using a proto/idl directory. But that does not scale (other IDLs) and is against not-introducing additional directories.

  • I recommend using singular instead of plural for all directory names. A lot of projects mix singular and plural directory names, e.g. LLVM. That should be avoided in the PFL, imo.
    Example: doc (instead of docs), test (instead of tests), etc.
    Reasons:

    1. Consistency: src and include are singular too.
    2. Compactness+Expressiveness: It safes one character per directory but the readability is the same.
  • What is the reason for using the .hpp file extension for header files? Though I agree that this makes things more explicit for C++, there are reasons against it.
    Reasons:

    1. The C++ Core Guidelines recommend using .h.
    2. Using .h for both C++ and C simplifies build system adoption.
  • I don't think that the build directory should be specified by a C++ filesystem layout convention.

    1. Against "best-practices": out-of-source by its strict definition means "outside of a project directory <project_name>", not <project_name>/_build.
    2. Inconsistency: If a build directory is mentioned, why is not install/stage directory mentioned?
    3. Scope: The PFL should focus on a C++ project filesystem source layout (keep the scope as narrow as possible).
      Therefore I suggest dropping all mentions of a build directory. If it is not dropped, it should be mentioned last at least (its the first item in section 1.3).
  • I do not have a strong opinion about external, data, tools, libs and extras yet. Do we really need that much directories? Also I do not understand why "submodules" are necessary (it seems it is a pretty rare use case for big code bases only - but I can always use multiple projects instead). Maybe I have to read the sections again.

  • I think using An Elaborated Option 2 is a very good and scalable approach (did I mention that I'm also using app for "production" executable files?). I like the idea to be able to add executable-specific source files in that directory. By doing that the library of the project is not "polluted" with project-local files only.

  • 1.2. Project Files: I suggest removing the sentence "Other files should not appear in the root of the project.". Though the sentence does not state shall (mandatory requirement), it is an optional requirement that would be violated by the existance of other pretty common files in the root directory.
    Examples:

    1. CHANGELOG.md: Keep a CHANGELOG
    2. CONTRIBUTING.md: Contributing Guidelines
  • 2.4. tests/: In my opinion the layout of that directory has to be specified by the PFL. Otherwise we have to consider that .cpp test source files are stored in multiple arbitrary subdirectories below that directory. Usually each .cpp test source file is compiled (with a main() entry point function) to a test executable.
    We have to consider that the same project provides header and source files for testing only (e.g. an Object Mother class). In my opinion they do not belong into the src/include directories, but below the test directory.
    Without a convention for the layout of that directory, it is unneccessary hard for the build system to determine which .cpp files have to be linked against the test framework (e.g. GTest) and which .cpp files are part of the testing library part of the project.
    I suggest specifying the directories (app, include and src) below test as follows (the rest is listed for illustration only):

    └───test
        ├───app
        │   │   simple_integration_test.cpp
        │   │
        │   └───complex_integration_test
        │       │   complex_integration_test.cpp
        │       │
        │       ├───include
        │       └───src
        ├───include
        │   └───fw
        │       └───testing
        │               my_test_util_class.h
        │               testing.h
        │
        └───src
            └───fw
                └───testing
                        my_test_util_class.cpp
    
  • 3.2.1. Where is the .test convention derived from?
    I don't like using dots in filenames (except at the beginning or for the extension) and I also think that is is very unusual. Using <name>_test.cpp would be better, since it could map to the class name used inside of that file (e.g. class StringTest in file string_test.h).
    Reasons:

    1. Standard-Conformance: There are coding standards out there (e.g. AUTOSAR) that do require such a 1:1-mapping between names.
    2. No "ambiguous" file extenstion (.test.cpp or .cpp?)

Again: I think the PFL is an awesome idea. The C++ ecosystem lacks so much compared to other (mostly managed) languages.

A common file system layout and a common/spread CoC build system (potentially using CMake) enforcing that layout would be super nice, imo.

If that CoC build system would (as opt-ins) support most of the open-source software C++ development tools (e.g. Cppcheck, Doxygen, clang-tidy), beginners could have a fun-time starting with Modern C++.

As it is now, I cannot recommend a (sane) beginner to start programming using C++, since dealing with the ecosystem is a pain in the a**.

Resources

Though, I did not completely read all of the following resources, I think they should be taken into account and/or referenced.

In addition, they may provide information for further improvements. I may add additional items in the future here.

My current filesystem suggestion

Note that the following listing does not include "resource" files yet, since it is pretty late here already.

But it includes everything related to source code files (except example).

  │   .clang-format
  │   .clang-tidy
  │   .cppcheck
  │   .gitignore
  │   CHANGELOG.md
  │   CONTRIBUTING.md
  │   LICENSE
  │   README.md
  │
  ├───app
  │   │   hello_world.cpp
  │   │   tower_of_hanoi.cpp
  │   │
  │   └───cli_greeter
  │       │   cli_greeter.cpp
  │       │
  │       ├───include
  │       │       greeter.h
  │       │
  │       └───src
  │               greeter.cpp
  │
  ├───include
  │   └───fw
  │           fw.h
  │           my_class.h
  │
  ├───src
  │   └───fw
  │           fw.cpp
  │           my_class.cpp
  │           my_class_test.cpp
  │
  └───test
      ├───app
      │   │   simple_integration_test.cpp
      │   │
      │   └───complex_integration_test
      │       │   complex_integration_test.cpp
      │       │
      │       ├───include
      │       └───src
      ├───include
      │   └───fw
      │       └───testing
      │               my_test_util_class.h
      │               testing.h
      │
      └───src
          └───fw
              └───testing
                      my_test_util_class.cpp

Regards

Allow querying into project structure info

This is an idea for a subcommand: pf info. Pitchfork has some knowledge about the project, such as the project base directory, or potentially (in the future) the components / source files. Adding a way to query this information would be helpful for scripting.

I am uncomfortable with the inconsistency of sometimes having a /src/ folder and sometimes not.

If a project with submodules is a directed graph, thus requiring all submodules to be siblings, then simply put all submodules in folders under the /src/ subfolder. For consistency, always place the main submodule in /src/main/, and place the other submodules in their own folders as sibling folders to /main/. If submodules are actually useful as separate libraries, then place them into subfolders of /lib/ and treat /lib/ with the rules currently ascribed to /external/. This, then, makes /external/ redundant, so it can be eliminated.

When most people think of "Libs" they think of "external libraries." However, within the context of Pitchfork," "Libs" takes on a different meaning, as "private submodules used only within the current project." This is also inconsistent.

The above suggestion does not take into consideration the debate as to whether external libraries should even be copied to the project folder. If it is decided that external libraries should not be copied to the project folder, the /lib/ folder could be used to hold simlinks to the original folders for those libraries, OR the /lib/ folder could also be eliminated and proper makefiles could be constructed to point to where the external libraries are stored.

Note: I am also using the singular version for all these folder names.

Multiple libs and apps per repo

There are numerous (actually, majority) of end-point projects (projects that are the end result) requiring to host multiple libraries and multiple applications.

For example, majority of production software is comprised of N in-house libs, M apps and P tests.

This structure does not fit any of those needs. At best, it fits well with (logically) single entities like libraries. But it also fails there too, for a tad bigger projects, like curl for example, which has at least one lib and one app.

Inability to clearly distinguish between logical entities in any folder-based structure is a big red flag. That's not really a structure, that's more like a glorified convention.

It defeats one of the core purposes: ability to navigate the folders structure without prior knowledge of a convention. It fails the understandability and compartmentalisation from the list of goals.

Test Failed: empty docs and third_party directories under tests/expected/ not included in git repository

The tests fail with this message:

../../tests/generate.cpp:43
...............................................................................

../../tests/generate.cpp:38: FAILED:
  CHECK_FALSE( diff )
with expansion:
  !Unexpected files in output directory:
    + docs
    + third_party

===============================================================================
test cases: 1 | 1 failed
assertions: 2 | 1 passed | 1 failed

I'm pretty sure this is because git doesn't commit empty directories; it tracks files, not directories.

If platform bindings go into `extras/` then extras aren't really "built upon" the main component(s)

w.r.t. the first paragraph of 4.4 extras/:

I get why platform bindings are not in libs/ as they're not always built and that's a requirement for the submodules in libs/. (Some people may never build the Windows bindings, others never build the Linux bindings ...) But typically one or another of them is always required for any given build. They're at the foundation of the project.

So I'm fine with them in extras but the wording of what goes in extras should be changed ...

Or maybe it's the requirement that stuff in libs/ is always built that should be relaxed ...

But actually, in my own project, I'm putting them as submodules in libs/.

(In fact, I have added another layer inside of libs/ where I group submodules by "category" - I may have multiple implementations of a given service interface, for example, so I put them together under, say, "storage" (one submodule for sqlite, one for filesystem, one for webdav, ...) - and in this way I'll have libs/platform/ and there will be under it windows and linux (macos can go into extras/ with any other contributed stuff...).)

(Pitchfork is well thought-out IMO, thanks for the effort!)

Conan hooks

The kind of enforceable project layout rules feel like a perfect fit for a Conan hook. It's more of a note than a feature request right now, but it could be a valuable for people who use Conan and want to enforce the PFL rules in their project.

Filesystem include issue

In the file src/pf/fs.hpp you differentiate between experimental and non-experimental versions of the filesystem include.
I have noticed that your *else branch is wrong:

#if STD_FS_IS_EXPERIMENTAL
#include <experimental/filesystem>
namespace pf {

namespace fs = std::experimental::filesystem;

}  // namespace pf
#else
#include <filesystem>
namespace pf {

namespace fs = std::experimental::filesystem;

}  // namespace pf
#endif

It should be: namespace fs = std::filesystem;
instead of: namespace fs = std::experimental::filesystem;

[spec] Add an entry for codegen files

Sometimes projects have sources that are not C++ but need to be generated into one. But they're also not data, they're still sources, so it'd be incorrect to put them alongside assets.
An example of such could be QML code. According to the [src.layout] section it'd be incorrect to put it alongside the C++ code.
What about adding a special section for a code generation folder?

Benchmarks

Hi,

I was recently changing the structure and tooling of an old project and thought that using a pitchfork layout would be a good enough idea. However, as I was about to handle the benchmarks directory of the project it occurred to me that there wasn't any such thing in PFL.

It would be interesting if benchmarks were at least discussed: I know that some people put them under either tests, examples or tools, but they often have a dedicated top-level subdirectory too and have their own sets of tooling and libraries.

Where to place source of other languages

Hello, I have a "big" project with mostly C++, but also some python files!

The spec says src is for compilable source (and I wouldnt want to put rogue python files in there anyway), but what would be the best place then? My best guess and what I did until now is a python folder in root basically acting like a src folder.

A similar issue I have now is for packaging. Multiple CMake files could go in a cmake folder. What about deb's control, postinst etc (those are basically package specs: dependencies, things to do on install etc), a debian folder maybe ?

It did make sense for python but now I feel like this is getting out of hand 😅

Feedback on project layout guidelines

Hey thanks for writing this list of guidelines for consistent structuring of C++ projects, which are strongly needed imo! They have recently been brought to my attention through an issue in my modern C++ starter template and I wanted to share my thoughts on the guidelines here as well.

  • Inconsistent naming conventions: In the proposition some directory names are singular (include, build, external), some are plural (tests, examples, extras), while others are abbreviated (src, libs, docs). IMO directory naming should be consistent so there is no confusion how to properly name directories.

  • Embedding external projects IMO external projects should never be embedded in a project, as this will create problems for library users downstream. E.g. if they wish to use two libraries A and B which both use C as an embedded library, their project will include C twice, thus breaking the ODR. Projects should always use a dependency management tool that fetches dependencies on demand and can be easily overwritten downstream (such as CPM.cmake) to allow users to resolve any issues.

  • No additional top-level directories the recommendations state that "other directories should not be present in the root directory, except for what is required by other tooling". I think this restriction is very project-dependent and reasonable exceptions should be allowed. E.g. I often use a script directory for non-development related scripts (e.g. files to run certain workflows with the compiled binary). My template even has a top-level standalone target executable that allows to run the library as a command-line utility. This is because the development of the standalone is so strongly coupled to the library that it makes no sense to create an additional project for it.

  • Derived targets I'm not sure if this is in the scope of the guidelines but I'd love to see a paragraph on derived targets (e.g. the tests). In many C++ projects (including my own) I've seen the habbit of adding derived projects from the library's build system (e.g. by including it in from the main CMakeLists.txt). IMO this should be strongly discouraged, as it inverts the dependency tree (the tests should actually depend on the library) and make the library harder to include from other projects, as we usually don't want the tests to be included.

  • Submodules If you are using submodules in a C / C++ project that cannot be modelled as an external dependency or project, it is a strong sign that the library itself needs refactoring. This is why I would avoid mentioning them at all in project guidelines.

I hope that the feedback makes sense and would love watch this project evolve!

Multiple Executables in Project

My use case is as follows: I have a selection of library based submodules. They are not completely standalone as there are dependencies among them, but they makes sense as submodules. I also will be generating multiple executables that use these libraries to do various things. There doesn't seem to be a way in the current spec to have "submodules" in the src directory. It makes logical sense to me that you put library submodules in the libs directory and executable submodules in the src directory.

Random illustrative example: if my project generated: libdisk.so libnetwork.so disk-add network-add the structure would be like:

|-- lib
|   \-- disk
|       \-- disk.cpp
|   \-- network
|       \-- network.cpp
|-- src
    \-- disk-add
        \-- main.cpp
    \-- network-add
        \-- main.cpp

Thoughts?

Missing directories include/ and tools/

If you're developing a library (not an application), then you want a root include directory which will be installed as public API on the system (this means you use <...> for them instead of "..." for headers in src/).

include/mylibrary/
include/mylibrary/mylibrary.hpp
include/mylibrary/mylibrary/specific_header.hpp

Users are recommended to include <mylibrary/mylibrary.hpp>

If a library has multiple modules (like boost), then the layout is:

include/myproject/
include/myproject/sublibrary1.hpp
include/myproject/sublibrary1/specific_header.hpp
include/myproject/sublibrary2.hpp
include/myproject/sublibrary2/specific_header.hpp

This is for larger projects with multiple library modules (that might be in separate repos or the same repo).

Having the include/ files available serves as a kind of public documentation.

The second issue, is there needs to be a tools/ directory for scripts, optional tooling, things used for development of the code but aren't necessarily part of the main distribution for the application/library.

[Feature Request] Add an installable add_pf_library cmake function

As the title says, it would be nice, if you could provide a add_pf_library(<name> <root-dir>) (and add_pf_executable) cmake function that just takes the root directory of a project as an argument, creates a cmake target with the appropriate name and adds the include directory and source files according to the layout specified in this proposal.

I wouldn't provide a lot of configuration options, because if the user has special requirements, he/she can just as easily create a matching cmake target manually.

non-source-code files in source directories

Section 3.3 of the specification states "No non-source-code files will should be placed or generated in any subdirectories of a source directory." however this conflicts with the requirements of some development tools.

In particular, files such as .clang-tidy, .clang-format and Doxyfile must be placed in particular locations in the source tree relative to files to which they apply.

It seems like the intent here is to exclude binary artifacts but the wording goes beyond that.

[spec] suggestion: move `.vscode`, `cmake`, … into a dedicated folder

Hello,
I really like the idea of this project. I think it can bring a lot to the C++ ecosystem.

When looking at the structure of this project, I think that it's inconsistent to have a .vscode and a cmake folder at the root of the directory. I think all files related to tooling should be moved to a dedicated folder. Given the list you proposed, I think it should be either tool or a new one dedicated to build system. I don't know however if all (most?) tools (cmake/meson/conan/qtcreator/visual studio/…) can handle to not have their folder at the root of the project.

where to put source files for PGO training programs

I have a library (a submodule under libs/) that I want to build with profile-guided optimization. To run the instrumented library to collect profile data, I plan to make a setup where I can choose from multiple small-ish training programs which call functions from the library. Where is a good place to put the source code for the training programs?

  • They definitely aren't "source code" in the sense of implementing any functionality of the library.
  • They aren't tests because they don't have anything to do with checking the correctness of the code.
  • They don't seem quite like "extras" since the library is the core part of the project, and the training programs are an essential part of its build process when doing PGO.
  • They definitely aren't data, but they are used to produce data (which shouldn't be checking into version control)
  • I do have an apps/ directory as discussed as one option in #30, but PGO training programs just don't feel like "apps" to me. They aren't useful or intended for anything except gathering representative profile data.

I'd like to hear what the authors of this spec think: Would it be "wrong" of me to add a new child directory inside the library's submodule directory just for pgo training program source code?

Name clashes

Great project! I wish everybody could use this layout. It's not perfect (because everyone has an opinion on this matter) but it's far more important to have a common standard than to continue the fragmentation.

Anyway, I note two name clashes:

  • First an internal name clash: the directories external and extras begin with the three same letters which is not convinient for people navigating through the sources with a console (and auto-completion). Maybe you could reconsider third_party as a viable alternative to external as the results of the poll indicated that third_party was OK. Note that examples is also a problem regarding auto-completion.
  • Second an external name clash: your tool is called pf like Packet Filter which is present on many systems where pitchfork could be used too. Maybe a rename like pfk could be ok.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.