From d7a83a1111ece79bf226950ede66417876809173 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Oct 2025 19:39:25 +0200 Subject: [PATCH] REVIEWED: RENAMED: Renamed tool `raylib_parser` to `rlparser` The tool can work with other libraries following `raylib.h` structure, keeping the `raylib_parser` name could be missleading. Also added an icon an reviewed Makefile an CI. --- .github/workflows/parse_api.yml | 4 +- tools/parser/Makefile | 44 ------- tools/{parser => rlparser}/LICENSE | 0 tools/rlparser/Makefile | 118 ++++++++++++++++++ tools/{parser => rlparser}/README.md | 24 ++-- .../output/raylib_api.json | 0 .../output/raylib_api.lua | 0 .../output/raylib_api.txt | 0 .../output/raylib_api.xml | 0 .../raylib_parser.c => rlparser/rlparser.c} | 14 +-- tools/rlparser/rlparser.ico | Bin 0 -> 2922 bytes tools/rlparser/rlparser.rc | 24 ++++ tools/rlparser/rlparser.rc.data | Bin 0 -> 4486 bytes 13 files changed, 163 insertions(+), 65 deletions(-) delete mode 100644 tools/parser/Makefile rename tools/{parser => rlparser}/LICENSE (100%) create mode 100644 tools/rlparser/Makefile rename tools/{parser => rlparser}/README.md (83%) rename tools/{parser => rlparser}/output/raylib_api.json (100%) rename tools/{parser => rlparser}/output/raylib_api.lua (100%) rename tools/{parser => rlparser}/output/raylib_api.txt (100%) rename tools/{parser => rlparser}/output/raylib_api.xml (100%) rename tools/{parser/raylib_parser.c => rlparser/rlparser.c} (99%) create mode 100644 tools/rlparser/rlparser.ico create mode 100644 tools/rlparser/rlparser.rc create mode 100644 tools/rlparser/rlparser.rc.data diff --git a/.github/workflows/parse_api.yml b/.github/workflows/parse_api.yml index c8665e1d4..ce7cb9f9a 100644 --- a/.github/workflows/parse_api.yml +++ b/.github/workflows/parse_api.yml @@ -32,6 +32,6 @@ jobs: set -x git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add tools/parser - git commit -m "Update raylib_api.* by CI" + git add tools/rlparser + git commit -m "rlparser: update raylib_api.* by CI" git push diff --git a/tools/parser/Makefile b/tools/parser/Makefile deleted file mode 100644 index ecfdb44ba..000000000 --- a/tools/parser/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -EXTENSION?=txt -FORMAT?=DEFAULT -.PHONY: all parse clean raylib_api - - -raylib_parser: raylib_parser.c - cc raylib_parser.c -o raylib_parser - -raylib_api: ../../src/raylib.h raylib_parser - FORMAT=DEFAULT EXTENSION=txt $(MAKE) raylib_api.txt - FORMAT=JSON EXTENSION=json $(MAKE) raylib_api.json - FORMAT=XML EXTENSION=xml $(MAKE) raylib_api.xml - FORMAT=LUA EXTENSION=lua $(MAKE) raylib_api.lua - -raylib_api.$(EXTENSION): ../../src/raylib.h raylib_parser - ./raylib_parser -i ../../src/raylib.h -o raylib_api.$(EXTENSION) -f $(FORMAT) -d RLAPI - -raymath_api.$(EXTENSION): ../../src/raymath.h raylib_parser - ./raylib_parser -i ../../src/raymath.h -o raymath_api.$(EXTENSION) -f $(FORMAT) -d RMAPI - -rlgl_api.$(EXTENSION): ../../src/rlgl.h raylib_parser - ./raylib_parser -i ../../src/rlgl.h -o rlgl_api.$(EXTENSION) -f $(FORMAT) -d RLAPI -t "RLGL IMPLEMENTATION" - -reasings_api.$(EXTENSION): ../../examples/others/reasings.h raylib_parser - ./raylib_parser -i ../../examples/others/reasings.h -o reasings_api.$(EXTENSION) -f $(FORMAT) -d EASEDEF - -raygui_api.$(EXTENSION): ../raygui.h raylib_parser - ./raylib_parser -i ../raygui.h -o raygui_api.$(EXTENSION) -f $(FORMAT) -d RAYGUIAPI -t "RAYGUI IMPLEMENTATION" - -parse: raylib_api.$(EXTENSION) raymath_api.$(EXTENSION) rlgl_api.$(EXTENSION) raygui_api.$(EXTENSION) - - -# `make parse` (and therefore `make all) requires -# rmem.h, physac.h and raygui.h to exist in the correct directory -# API files for individual headers can be created likeso, provided the relevant header exists: -# FORMAT=JSON EXTENSION=json make raygui_api.json -all: raylib_parser - FORMAT=DEFAULT EXTENSION=txt $(MAKE) parse - FORMAT=JSON EXTENSION=json $(MAKE) parse - FORMAT=XML EXTENSION=xml $(MAKE) parse - FORMAT=LUA EXTENSION=lua $(MAKE) parse - -clean: - rm -f raylib_parser *.json *.txt *.xml *.lua diff --git a/tools/parser/LICENSE b/tools/rlparser/LICENSE similarity index 100% rename from tools/parser/LICENSE rename to tools/rlparser/LICENSE diff --git a/tools/rlparser/Makefile b/tools/rlparser/Makefile new file mode 100644 index 000000000..a645f7f41 --- /dev/null +++ b/tools/rlparser/Makefile @@ -0,0 +1,118 @@ +EXTENSION?=txt +FORMAT?=DEFAULT +.PHONY: all parse clean raylib_api + +# Determine PLATFORM_OS +# No uname.exe on MinGW!, but OS=Windows_NT on Windows! +# ifeq ($(UNAME),Msys) -> Windows +ifeq ($(OS),Windows_NT) + PLATFORM_OS = WINDOWS +else + UNAMEOS = $(shell uname) + ifeq ($(UNAMEOS),Linux) + PLATFORM_OS = LINUX + endif + ifeq ($(UNAMEOS),FreeBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),OpenBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),NetBSD) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),DragonFly) + PLATFORM_OS = BSD + endif + ifeq ($(UNAMEOS),Darwin) + PLATFORM_OS = OSX + endif +endif + +# Define default C compiler: CC +#------------------------------------------------------------------------------------------------ +CC = gcc +ifeq ($(PLATFORM_OS),OSX) + # OSX default compiler + CC = clang +endif +ifeq ($(PLATFORM_OS),BSD) + # FreeBSD, OpenBSD, NetBSD, DragonFly default compiler + CC = clang +endif + +# Define default make program: MAKE +#------------------------------------------------------------------------------------------------ +MAKE ?= make +ifeq ($(PLATFORM_OS),WINDOWS) + MAKE = mingw32-make +endif + +# Define compiler flags: CFLAGS +#------------------------------------------------------------------------------------------------ +CFLAGS = -Wall -std=c99 +#CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes + +ifeq ($(BUILD_MODE),DEBUG) + CFLAGS += -g -D_DEBUG +else + ifeq ($(PLATFORM_OS),OSX) + CFLAGS += -O2 + else + CFLAGS += -s -O2 + endif +endif +ifeq ($(PLATFORM_OS),WINDOWS) + # NOTE: The resource .rc file contains windows executable icon and properties + CFLAGS += rlparser.rc.data +endif + +# Define processes to execute +#------------------------------------------------------------------------------------------------ +# rlparser compilation +rlparser: rlparser.c + $(CC) rlparser.c -o rlparser $(CFLAGS) + +# rlparser execution: [raylib.h] parse, generating some output files +raylib_api: ../../src/raylib.h rlparser + FORMAT=DEFAULT EXTENSION=txt $(MAKE) raylib_api.txt + FORMAT=JSON EXTENSION=json $(MAKE) raylib_api.json + FORMAT=XML EXTENSION=xml $(MAKE) raylib_api.xml + FORMAT=LUA EXTENSION=lua $(MAKE) raylib_api.lua + +# rlparser execution: [raylib.h] parse, generating some output files +raylib_api.$(EXTENSION): ../../src/raylib.h rlparser + ./rlparser -i ../../src/raylib.h -o raylib_api.$(EXTENSION) -f $(FORMAT) -d RLAPI + +# rlparser execution: [rlgl.h] parse, generating some output files +rlgl_api.$(EXTENSION): ../../src/rlgl.h rlparser + ./rlparser -i ../../src/rlgl.h -o rlgl_api.$(EXTENSION) -f $(FORMAT) -d RLAPI -t "RLGL IMPLEMENTATION" + +# rlparser execution: [raymath.h] parse, generating some output files +raymath_api.$(EXTENSION): ../../src/raymath.h rlparser + ./rlparser -i ../../src/raymath.h -o raymath_api.$(EXTENSION) -f $(FORMAT) -d RMAPI + +# rlparser execution: [reasings.h] parse, generating some output files +reasings_api.$(EXTENSION): ../../examples/others/reasings.h rlparser + ./rlparser -i ../../examples/others/reasings.h -o reasings_api.$(EXTENSION) -f $(FORMAT) -d EASEDEF + +# rlparser execution: [raygui.h] parse, generating some output files +raygui_api.$(EXTENSION): ../raygui.h rlparser + ./rlparser -i ../raygui.h -o raygui_api.$(EXTENSION) -f $(FORMAT) -d RAYGUIAPI -t "RAYGUI IMPLEMENTATION" + +# Target to generate required APIs output files +parse: raylib_api.$(EXTENSION) raymath_api.$(EXTENSION) rlgl_api.$(EXTENSION) raygui_api.$(EXTENSION) + +# "make parse" (and therefore "make all") requires +# raygui.h and reasings_api.h to exist in the correct directory +# API files for individual headers can be created likeso, provided the relevant header exists: +# FORMAT=JSON EXTENSION=json make raygui_api.json +all: rlparser + FORMAT=DEFAULT EXTENSION=txt $(MAKE) parse + FORMAT=JSON EXTENSION=json $(MAKE) parse + FORMAT=XML EXTENSION=xml $(MAKE) parse + FORMAT=LUA EXTENSION=lua $(MAKE) parse + +# Clean rlparser and generated output files +clean: + rm -f rlparser *.json *.txt *.xml *.lua diff --git a/tools/parser/README.md b/tools/rlparser/README.md similarity index 83% rename from tools/parser/README.md rename to tools/rlparser/README.md index 86cdfdd5b..0e4f9b739 100644 --- a/tools/parser/README.md +++ b/tools/rlparser/README.md @@ -1,4 +1,4 @@ -# raylib parser +# rlparser - raylib parser This parser scans [`raylib.h`](../src/raylib.h) to get information about `defines`, `structs`, `enums` and `functions`. All data is separated into parts, usually as strings. The following types are used for data: @@ -8,16 +8,16 @@ All data is separated into parts, usually as strings. The following types are us - `struct StructInfo` - `struct EnumInfo` -Check `raylib_parser.c` for details about those structs. +Check `rlparser.c` for details about those structs. ## Command Line ``` ////////////////////////////////////////////////////////////////////////////////// // // -// raylib API parser // +// rlparser - raylib header API parser // // // -// more info and bugs-report: github.com/raysan5/raylib/parser // +// more info and bugs-report: github.com/raysan5/raylib/tools/rlparser // // // // Copyright (c) 2021-2025 Ramon Santamaria (@raysan5) // // // @@ -25,7 +25,7 @@ Check `raylib_parser.c` for details about those structs. USAGE: - > raylib_parser [--help] [--input ] [--output ] [--format ] + > rlparser [--help] [--input ] [--output ] [--format ] OPTIONS: @@ -50,19 +50,19 @@ OPTIONS: EXAMPLES: - > raylib_parser --input raylib.h --output api.json + > rlparser --input raylib.h --output api.json Process to generate - > raylib_parser --output raylib_data.info --format XML + > rlparser --output raylib_data.info --format XML Process to generate as XML text data - > raylib_parser --input raymath.h --output raymath_data.info --format XML --define RMAPI + > rlparser --input raymath.h --output raymath_data.info --format XML --define RMAPI Process to generate as XML text data ``` ## Constraints -This parser is specifically designed to work with raylib.h, so, it has some constraints: +`rlparser` is specifically designed to work with `raylib.h`, so, it has some constraints: - Functions are expected as a single line with the following structure: ``` @@ -91,7 +91,7 @@ This parser is specifically designed to work with raylib.h, so, it has some cons ``` _NOTE: For enums, multiple options are supported:_ - + - If value is not provided, ( + 1) is assigned - Value description can be provided or not @@ -103,5 +103,7 @@ This parser **does not require `` library**, all data is parsed direct ### LICENSE: zlib/libpng -raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. Check [LICENSE](LICENSE) for further details. +raylib-parser is licensed under an unmodified zlib/libpng license, which is an OSI-certified, BSD-like license that allows static linking with closed source software. + +Check [LICENSE](LICENSE) for further details. diff --git a/tools/parser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json similarity index 100% rename from tools/parser/output/raylib_api.json rename to tools/rlparser/output/raylib_api.json diff --git a/tools/parser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua similarity index 100% rename from tools/parser/output/raylib_api.lua rename to tools/rlparser/output/raylib_api.lua diff --git a/tools/parser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt similarity index 100% rename from tools/parser/output/raylib_api.txt rename to tools/rlparser/output/raylib_api.txt diff --git a/tools/parser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml similarity index 100% rename from tools/parser/output/raylib_api.xml rename to tools/rlparser/output/raylib_api.xml diff --git a/tools/parser/raylib_parser.c b/tools/rlparser/rlparser.c similarity index 99% rename from tools/parser/raylib_parser.c rename to tools/rlparser/rlparser.c index 4b5fe1625..2432af4af 100644 --- a/tools/parser/raylib_parser.c +++ b/tools/rlparser/rlparser.c @@ -1,28 +1,28 @@ /********************************************************************************************** - raylib API parser + rlparser - raylib header API parser, extracts API information as separate tokens This parser scans raylib.h to get API information about defines, structs, aliases, enums, callbacks and functions. All data is divided into pieces, usually as strings. The following types are used for data: - - struct DefineInfo - struct StructInfo - struct AliasInfo - struct EnumInfo - struct FunctionInfo + + WARNING: This parser is specifically designed to work with raylib.h, and has some contraints + in that regards. Still, it can also work with other header files that follow same file structure + conventions as raylib.h: rlgl.h, raymath.h, raygui.h, reasings.h CONSTRAINTS: - This parser is specifically designed to work with raylib.h, so, it has some constraints: - Functions are expected as a single line with the following structure: - ( , ); - Be careful with functions broken into several lines, it breaks the process! + WARNING: Be careful with functions broken into several lines, it breaks the process! - Structures are expected as several lines with the following form: - typedef struct { ; @@ -31,7 +31,6 @@ } ; - Enums are expected as several lines with the following form: - typedef enum { = , @@ -45,7 +44,6 @@ - Value description can be provided or not OTHER NOTES: - - This parser could work with other C header files if mentioned constraints are followed. - This parser does not require library, all data is parsed directly from char buffers. diff --git a/tools/rlparser/rlparser.ico b/tools/rlparser/rlparser.ico new file mode 100644 index 0000000000000000000000000000000000000000..37f2af6b65b7ad4ad7a2c6c35b6db7d447d17b69 GIT binary patch literal 2922 zcmZQzU}WH6fB*%CL}mttHUcVM28QR%3=9bg5Pk|H14BP61A~JDgm2Es z!0?%kfx*B4!e?e=V9?@VU{Fwi@NY0MFz9kJFi1#1_y-vn7+AR&7z6|${3Q$w49B<_ z7&-&|+^U;W-)dhho7>yL#HiUb%U{^xyrb6oW66h}mALD9&7mVy+nZRfQ4@AqS7 z>7;(-MB`Au`RsrBzx8E*?=^zNvAcau-gn#oFe#itG(n$Xt=MXgbqFUhFrvEyEK*fH zot>Qtl%X8{t#3_W-|GA1#L{3%aIW@r^>bP0l+c8k!9afwND?;KaWAd*|=_ZnTYIVqj@t z5MW?(VBl!*J^ib6s#;!boErn90$f~VZ+ic`H#WQsvUvxta)7KQk>GG=aIj!vI3&m* z(8thFz{1d?%%C8{$ncPZ0V<{D&H!@+vdtW*9Jq_n#AP#fPYUmMoeT8_17pC)FZZHe zU#@$)6C|{tWX9WCJ!v--T|QrG6Y~$He<}OOz`?*6VD|rh)tp!I?u-UZP-SU#j~N_5 za^Qft5Xo@WUgHD@m;(;2jEMShfuaM07~yGBoA!b zx7IK5^(OQddbjxW_pklb4uJ9{1CzmXS#t(8 zkaq&i8~o}kGMT_u22{q!%+B)o6l&Z`AdErPnFBbCS7jF7V_;zT2My!fhJ1$%cv=%D z>`<^)Pk4XsUUq@MfOgi^W!tXqnQmVksyTnok+RFLUswK*VUycFQJtTGft%s-pKbF# z*w}V3Ffa%({fOVZHaXk>wcG>qMvbOFLMvP*++j7t79I1!>1m5@%c{oMql5 zutazv56e#$T|>ILcLprrXY;Zak-trP2O(w!@|E#>XIZ6)9Q zIQ`R}pZ^)1?!@L;wY6%x95Ckfnio=K&Kx5>N$Ek*38ssC*tT$VC|y%X@LL$ga>X#J zx#2Z)5KD^kWQ7FlLQSTsDH@Ik&O2GQbSJ*cJ@eeei-D0v-~n@ix$^7Pv+I-ttaP94 z+fgQats&HJ`L#m(-c22x3Jg3GUY&TC|IDtx;me=%d*g5WM=-NguxF%ex-oDie7rtE z@C9!H)7rhR9ogL2y+3=9k%5PzKwHRNkB;JDJlzw0;C_jm99w*9|i;pOH1F(WaDgT356@_h1c z@#6~TAIUdN(a(4|=i5Qy2|v?7oV}l zx{v-_2zUV0!V~~|K>qXpL`jqIq!EBF`-%8G9Pai znQM6dgKFzLJ+V7H@=QC;E+?D~tZy!zVHC`HhEXRe?Lg-Yg&?H`C-4j*|nzp o@wdj)zj_+4um>^h_GUP1E1+29`}?0XySKX*$Go-s<|Dfi01jvxl>h($ literal 0 HcmV?d00001 diff --git a/tools/rlparser/rlparser.rc b/tools/rlparser/rlparser.rc new file mode 100644 index 000000000..a5bb5b7ad --- /dev/null +++ b/tools/rlparser/rlparser.rc @@ -0,0 +1,24 @@ +IDI_APP_ICON ICON "rlparser.ico" +1 VERSIONINFO +FILEVERSION 5,5,0,0 +PRODUCTVERSION 5,5,0,0 +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" // English US + BEGIN + VALUE "CompanyName", "raylib technologies" + VALUE "FileDescription", "rlparser | raylib header API parser" + VALUE "FileVersion", "1.0" + VALUE "InternalName", "rlparser" + VALUE "LegalCopyright", "(c) 2025 Ramon Santamaria (@raysan5)" + VALUE "OriginalFilename", "rlparser" + VALUE "ProductName", "rlparser" + VALUE "ProductVersion", "1.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 // English US + END +END \ No newline at end of file diff --git a/tools/rlparser/rlparser.rc.data b/tools/rlparser/rlparser.rc.data new file mode 100644 index 0000000000000000000000000000000000000000..1b5cc0c02405e85446ee9dcda9ca75dc3d57d458 GIT binary patch literal 4486 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 literal 0 HcmV?d00001