{"id":15015401,"url":"https://github.com/rudojaksa/pcpp","last_synced_at":"2026-04-07T05:31:18.322Z","repository":{"id":239493081,"uuid":"799675624","full_name":"rudojaksa/pcpp","owner":"rudojaksa","description":"Simple Perl (Python/C/C++) preprocessor","archived":false,"fork":false,"pushed_at":"2024-09-08T21:15:37.000Z","size":79,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-13T00:18:30.242Z","etag":null,"topics":["amalgamation","cpp","perl","preprocessor"],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rudojaksa.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-12T20:44:28.000Z","updated_at":"2024-09-08T21:15:41.000Z","dependencies_parsed_at":"2024-08-02T22:58:46.031Z","dependency_job_id":"4590b037-0755-432d-9bf5-e84003ac8ce0","html_url":"https://github.com/rudojaksa/pcpp","commit_stats":null,"previous_names":["rudojaksa/pcpp"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/rudojaksa/pcpp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fpcpp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fpcpp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fpcpp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fpcpp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rudojaksa","download_url":"https://codeload.github.com/rudojaksa/pcpp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rudojaksa%2Fpcpp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31501903,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T03:10:19.677Z","status":"ssl_error","status_checked_at":"2026-04-07T03:10:13.982Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amalgamation","cpp","perl","preprocessor"],"created_at":"2024-09-24T19:47:24.092Z","updated_at":"2026-04-07T05:31:18.298Z","avatar_url":"https://github.com/rudojaksa.png","language":"Perl","readme":"# Simple Perl (Python/C/C++) preprocessor\n\nThis simple preprocessor handles in-comments include directives.  Such include\nstatements that are contained inside comments provide an additional level of\ncode organization, above Perl's `require` and `use`, Python's `import`, or\nC/C++ `#include` native mechanisms.  However, both these mechanisms (native and\npcpp) can coexist together.  Or, the pcpp can be used instead of the native\nmechanism.\n\nIn the following Perl and C examples the \"abc\" code will be copy-pasted into\nthe source code by the pcpp, while the \"xyz\" code will be handled by native\ninclude mechanisms:\n\n``` perl\n# Perl usage\n# include \"abc.pl\"\nrequire \"xyz.pl\";\n```\n\n``` python\n# Python usage\n# include \"abc.py\"\nimport xyz\n```\n\n``` c\n// C/C++ usage\n// include \"abc.h\"\n# include \"xyz.h\";\n```\n\nThe `pcpp` is a simple tool, although this description seems long, it only\nhandles:\n\n * include directives,\n * removal of triple-comments,\n * nothing else.\n\n### Why to \"compile\" Perl or Python?\n\nTo \"use\" the pcpp pre-processed code it is necessary to run the pcpp first,\nlike:\n\n``` sh\npcpp abc.in.pl \u003e abc.pl\nperl abc.pl\n```\n\nThis looks as if we first \"compile\" the bunch of Perl source files into the\n\"executable\" Perl file and only then run it.  Similarly, a C code has to be\ncompiled before it can be executed.  It is a disadvantage as it requires the\nextra step `pcpp abc.in.pl`.  But the following step `perl abc.pl` becomes\nsimpler:\n\n * now the abc\\.pl doesn't require the dependent .pl files to be installed,\n * the abc\\.pl stays an interpreted language code that can be fixed if needed\n   (comments stay in as well).\n\nThe same holds for Python.  Pcpp-ing is some kind of simple code amalgamation\nor a \"static linker\" for Perl/Python.  In C/C++ the pcpp is useful if you want\nto hide something from the cpp preprocessor.\n\nAnother reason to use pcpp instead of native require/use/import is that the\npcpp processing logic is simpler.  One more reason is that such include process\ncannot be skewed at the use-time and run-time.\n\n### In-comment directives\n\nHiding the pcpp directives in comments allows to avoid conflicts with the main\nlanguage interpreter/compiler/preprocessor, with IDEs or editing modes.\nFurther, this increases the number of comments ;-)\n\nMultiple filenames in the single include directive line are allowed, quoting is\noptional, whitespace between the hash and the \"include\" word is optional:\n\n```\n#include abc.pl xyz.pl \"efg.pl\"\n```\n\nThe additional text after the filename(s) is a comment and is ignored,\nfilenames have to be identified by the .pl (or .py/.h) suffix or have to be\nquoted for the parser to find the beginning of the comment:\n\n```\n# include abc.pl xyz.pl comment text which is ignored\n# include abc.py xyz.py # visualy more noticeable comment\n// include abc.h comment in C/C++\n```\n\nMultiple hashes (slashes) are not accepted, the following code are just\ncomments without any effect:\n\n```\n## include abc.pl\n### include abc.pl\n#### include abc.pl\n/// include abc.h\n//// include abc.h\n```\n\nIncluded content in the pcpp output is \"watermarked\" by the `# included` and\n`# end` comments/directives (in C/C++ `// included` and `// end`):\n\n``` perl\n# included \"abc.pl\"\n...\n# end \"abc.pl\"\n```\n\nIndentation of the include statement is propagated into output.  For instance a\ntwo-space indentation of the hash of the include statement in perl code:\n\n``` perl\nsome(code);\n  # include abc.pl\n```\n\nwill lead to adding two spaces to the original indentation in the included\nfile:\n\n``` perl\nsome(code);\n  # included abc.pl\n  originally_unindented_abc_pl(code);\n  following_line();\n  ...\n```\n\nThe language is autodetected according to the suffix of the input file: `.pl`,\n`.py`, `.c`, or `.c++`.\n\n### Paths resolving\n\nInclude paths can be specified as a filename only `# include abc.pl` or\nspecifying also a part of the path `# include xy/abc.pl` or `# include\nyz/abc.pl` to distinguish between equal filenames in different directories.\n\nThe path resolving algorithm distinguishes between files included from the\ntop-level source or from a file which is included.  Path resolving algorithm\nconsiders paths relative to the current working directory (CWD) or to the\ndirectory of the currently parsed file.  The algorithm is:\n\n1. try direct path for the top-level file includes (CWD relative),\n2. try path relative to currently active included file (to allow incorporation of whole code trees with relative includes working),\n3. try CWD-relative paths even for not-top-level files (to allow programmer to think about files as relative from CWD),\n4. try to find files recursively in any subdirectory of the CWD in the depth order (to allow to skip dirnames for unique filenames),\n5. strip the directory part from the included file name, and try to find it just by the filename (just a plan-B for wrong dirnames when moving files).\n\nIn the case of conflict, i.e. `# include \"abc.pl\"` where two `abc.pl` files are\navailable, the first one is chosen: `./abc.pl` is the direct path so it has a\nhigher priority than the `xy/abc.pl`.\n\nDouble includes are automatically avoided by the `pcpp`.  Any included file is\ncopy-pasted to the output only once, on the place of the first appearance of\nits include statement.\n\nMissing include files are silently ignored (by default), or reported in the\nverbose mode (-v switch).\n\n### Triple comments\n\nPcpp preserves comments to allow the Perl or Python output code to be readable\nas best as possible to allow the output to be hacked/fixed.\n\nHowever, to allow the programmer to request the removal of comments from the\noutput, we introduce the \"triple comments\":\n\n```\n### this line will be removed from the Perl/Python code by pcpp\n/// this line will be removed from the C/C++ code by pcpp\n#### but this will be kept\n## this will be kept too\n```\n\nTriple comments are removed together with preceding empty lines by pcpp.\n\n### Debugger problem\n\nUnfortunately, Perl or Python don't know how to translate line numbers from\npcpp processed code back to the original code.  So debugging requires checking\nthe pcpp processed code, not the code you wrote.\n\n### Uninclude\n\nWatermarked pcpp output allows the removal of included parts and return to the\noriginal source code using the `uninclude` tool.  This can be useful when\nbuilding \"libraries\" which can recursively pack all dependencies, which can be\nstripped off when not needed (when already provided by another \"library\").\n\nUninclude of multi-level included files is flattened to a single level, for\ninstance the following included content:\n\n```\n# included abc.pl\n  xyz\n  # included def.pl\n    uid\n  # end def.pl\n  hjk\n# end abc.pl\n```\n\nwill be flattened by uninclude to:\n\n```\n# include abc.pl\n# include def.pl\n```\n\nwhich when included back will become:\n\n```\n# included abc.pl\n  xyz\n  hjk\n# end abc.pl\n# included def.pl\n  uid\n# end def.pl\n```\n\n### Pcpp in Makefile\n\nExample to make `xyz` from its source `xyz.pl` and two included files:\n\n``` makefile\nxyz: xyz.pl inc1.pl inc2.pl\n\techo '#!/usr/bin/perl' \u003e $@\n\tpcpp $\u003c \u003e\u003e $@\n\t@chmod 755 $@\n\t@sync # to ensure the result is saved before being used in the next rule\n```\n\n 1. generate #! interpreter identifier\n 2. build `xyz` from `xyz.pl`\n 3. make it executable\n 4. sync the result before it is used by another makefile rule (otherwise it can be incomplete)\n\nMore complex example:\n\n``` makefile\nOUTPUT := xyz\nDEPENDENCIES := $(shell pcpp -lp $(OUTPUT:%=%.pl))\nSIGN := \"$(PKGNAME) $(AUTHOR)\"\nDATE := $(shell date '+%Y-%m-%d')\n\n$(OUTPUT): %: %.pl $(DEPENDENCIES) Makefile\n\techo -e '#!/usr/bin/perl' \u003e $@\n\techo -e \"# $@ generated from $(PKGNAME)/$\u003c $(DATE)\\n\" \u003e\u003e $@\n\techo -e '$$SIGN = $(SIGN);\\n' \u003e\u003e $@\n\tpcpp $\u003c \u003e\u003e $@\n\t@chmod 755 $@\n\t@sync\n```\n\n * `DEPENDENCIES` are a list of files to be included obtained by `pcpp -lp`\n * `SIGN` is a variable made available from Makefile into the script\n\n### Dependency files\n\nThe `pcpp -d target_name` can be used to generate a dependency file for\nMakefile.  Compared to the `-lp` option, the `-d` and `-dd` options also add\nthe input file into the list and nonexistent files too.  Nonexistent include\nfiles are files that will be generated by the Makefile.  A full path is\nrequired for them to work properly (relative path is ok if it is complete).\nExample Makefile:\n\n``` makefile\n# require rebuild of the dependencies file .abc.d when processing abc.pl\n%: %.pl .%.d\n\techo -e '#!/usr/bin/perl' \u003e $@\n\tpcpp -v $\u003c \u003e\u003e $@\n\n# save dependencies into .abc.d for the abc.pl source of the abc target\n.%.d: %.pl\n\tpcpp -d $(\u003c:%.pl=%) $\u003c \u003e $@\n\n# include generated dependencies but don't fail if they are missing\n-include .abc.d\n```\n\nNext table lists `pcpp` reporting options, and which files they report.  Direct\nfiles are these loaded according to the command-line request, not by the\ninclude directive.  Missing files are those not found, by requested by the\ninclude directive.\n\n```\n          | where  | direct | found | missing | redundant\n----------------------------------------------------------\n  -v/vv/l | stderr |  yes   |  yes  |  yes X    |   yes\n-ln/l1/lp | stdout |   no   |  yes  |  no   X  |   no\n   -d/-dd | stdout |  yes   |  yes  |  yes X   |   no X\n```\n\n### See also\n\n\u0026nbsp;\u0026nbsp; [pcpp -h](pcpp.md)  \n\u0026nbsp;\u0026nbsp; [uninclude -h](uninclude.md)  \n\n### Installation\n\nFiles `pcpp` and `uninclude` are standalone Perl scripts, which can be copied\nto any `/bin` directory for a system-wide installation.\n\n### Example\n\nThe pcpp itself is processed by the pcpp, so its source code is an example of\nhow to use the pcpp.\n\n\u003cbr\u003e\u003cdiv align=right\u003e\u003ci\u003eR.Jaksa 2008,2024\u003c/i\u003e\u003c/div\u003e\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frudojaksa%2Fpcpp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frudojaksa%2Fpcpp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frudojaksa%2Fpcpp/lists"}