Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/demo-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ jobs:
working-directory: source/modules/antono2/imgui
run: |
v run setup.vsh --check
v run generate.vsh --help
./scripts/check_upstream_variant.sh
- name: Select package variant
id: variant
Expand Down
2 changes: 1 addition & 1 deletion QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ v run build_vimgui.vsh --linkage shared --glfw bundled --glfw-version 3.4

## Regenerating bindings

Binding regeneration is maintainer-oriented. Run `./generate_v.sh` only when
Binding regeneration is maintainer-oriented. Run `v run generate.vsh` only when
updating the generated ImGui or ImPlot API. It translates the generated API
committed by the pinned upstream submodules; LuaJIT is required only with the
advanced `--regenerate-c` option. Use `./scripts/update_upstream.sh docking` on
Expand Down
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,14 @@ developers; they do not need to multiply the end-user demo downloads.

```bash
# Go to the installed antono2/imgui module
./generate_v.sh
v run generate.vsh
```

`generate_v.sh` regenerates both V bindings from the generated C API committed
`generate.vsh` regenerates both V bindings from the generated C API committed
by the pinned cimgui/cimplot revisions, then builds `libvimgui`. It therefore
does not require LuaJIT for a normal upstream refresh. Pass `--regenerate-c`
only when intentionally rerunning the upstream Lua generators; that advanced
mode requires LuaJIT. `v generate.vsh` is retained as a compatibility entry
point and delegates to the same canonical script.
mode requires LuaJIT.

Maintainers can update either line reproducibly with:

Expand All @@ -151,9 +150,7 @@ Maintainers can update either line reproducibly with:
```

To only rebuild the native library after a system upgrade or on an older Linux
distribution, run `v run build_vimgui.vsh`. The Bash `build_vimgui.sh` helper
remains available as a bootstrap fallback on Unix-like machines where V is not
yet in `PATH`.
distribution, run `v run build_vimgui.vsh`.

## Thanks
Thank you [@ryoskzypu](https://github.com/ryoskzypu) - from #regex on [libera.chat](https://libera.chat/) - for loving perl and helping people out.
56 changes: 0 additions & 56 deletions build_vimgui.sh

This file was deleted.

19 changes: 16 additions & 3 deletions build_vimgui.vsh
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,27 @@ fn run(parts []string) {
}

mut linkage := os.getenv('VIMGUI_LINKAGE')

if linkage == '' {
linkage = 'shared'
}

mut glfw_provider := os.getenv('VIMGUI_GLFW_PROVIDER')

if glfw_provider == '' {
glfw_provider = 'system'
}

mut glfw_version := os.getenv('VIMGUI_GLFW_VERSION')

if glfw_version == '' {
glfw_version = '3.3'
}

args := os.args[1..]

mut index := 0

for index < args.len {
match args[index] {
'--linkage' {
Expand Down Expand Up @@ -73,6 +80,7 @@ if linkage !in ['shared', 'static'] {
eprintln('linkage must be shared or static')
exit(2)
}

if glfw_provider !in ['system', 'bundled'] {
eprintln('glfw provider must be system or bundled')
exit(2)
Expand All @@ -81,29 +89,35 @@ if glfw_provider !in ['system', 'bundled'] {
if !os.is_file(os.join_path(repo_dir, 'CMakeLists.txt'))
|| !os.is_file(os.join_path(repo_dir, 'cimgui', 'cimgui.cpp'))
|| !os.is_file(os.join_path(repo_dir, 'cimplot', 'cimplot.cpp')) {
eprintln('Missing cimgui or cimplot sources. Run generate_v.sh first (or initialise the submodules).')
eprintln('Missing cimgui or cimplot sources. Run `v run generate.vsh` first (or initialise the submodules).')
exit(1)
}

static_build := if linkage == 'static' { 'ON' } else { 'OFF' }

mut no_export := 'ON'

$if windows {
// A Windows DLL needs cimgui/cimplot API exports and an import library.
no_export = 'OFF'
}

build_type := if os.getenv('CMAKE_BUILD_TYPE') == '' {
'Release'
} else {
os.getenv('CMAKE_BUILD_TYPE')
}

safe_glfw_version := glfw_version.replace('..', '_').replace('/', '_').replace('\\', '_')

build_dir := os.join_path(repo_dir, 'build', '${linkage}-${glfw_provider}-${safe_glfw_version}')

output_dir := os.join_path(repo_dir, 'lib')

os.mkdir_all(build_dir) or {
eprintln('Could not create build directory ${build_dir}: ${err}')
exit(1)
}

run([
'cmake',
'-S',
Expand All @@ -118,5 +132,4 @@ run([
'-DCIMGUI_NO_EXPORT=${no_export}',
])
run(['cmake', '--build', build_dir, '--config', build_type, '--parallel'])

println('Built vimgui in ${output_dir} (linkage: ${linkage}, GLFW: ${glfw_provider}, version: ${glfw_version})')
118 changes: 109 additions & 9 deletions generate.vsh
Original file line number Diff line number Diff line change
@@ -1,16 +1,116 @@
#!/usr/bin/env -S v
#!/usr/bin/env -S v run

// Canonical ImGui/ImPlot binding generator.

// Compatibility entry point for the canonical Bash generator. Keeping the
// generation logic in one implementation prevents the two paths from
// producing subtly different bindings.
import os

const repo_dir = @DIR
const c2v_flags = '-DSTATIC_BUILD=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=ON -DIMGUI_STATIC=OFF -DCIMGUI_NO_EXPORT=ON -DCIMGUI_USE_GLFW=ON'

fn usage() {
println('Usage: v run generate.vsh [--regenerate-c]')
println('By default, translate the generated C API committed by cimgui/cimplot.')
}

fn run_at(command string, directory string) ! {
println('\n> ${command}')
result := os.execute('cd ${os.quoted_path(directory)} && ${command}')
if result.output.trim_space() != '' {
println(result.output.trim_right('\r\n'))
}
if result.exit_code != 0 {
return error('command failed with exit code ${result.exit_code}')
}
}

fn remove_file(path string) ! {
if os.is_file(path) {
os.rm(path)!
}
}

fn copy_matching(pattern string, destination string) ! {
files := os.glob(pattern) or { return error('could not expand ${pattern}: ${err}') }
if files.len == 0 {
return error('no files matched ${pattern}')
}
for source in files {
os.cp(source, os.join_path(destination, os.file_name(source)))!
}
}

fn add_translation_fix(path string) ! {
program := r's/(struct\s[\w\d]+\s\{[^\}]+(?:union\s+\{[^\}]+\};[^\}]+)?\};\s)(typedef\s(?!struct|enum)[^\n]+)/$1\n\nstruct ____TRANSLATIONFIX____;\n$2/g'
run_at('perl -p -i -g -e ${os.quoted_path(program)} ${os.quoted_path(path)}', repo_dir)!
}

fn main() {
mut parts := [os.quoted_path(os.join_path(@DIR, 'generate_v.sh'))]
mut regenerate_c := false
for arg in os.args[1..] {
parts << os.quoted_path(arg)
match arg {
'--regenerate-c' {
regenerate_c = true
}
'-h', '--help' {
usage()
return
}
else {
eprintln('Unknown option: ${arg}')
usage()
exit(2)
}
}
}

println('Generating bindings in ${repo_dir}')
remove_file(os.join_path(repo_dir, 'cimgui', 'CMakeCache.txt')) or { panic(err) }
remove_file(os.join_path(repo_dir, 'cimplot', 'CMakeCache.txt')) or { panic(err) }
remove_file(os.join_path(repo_dir, 'CMakeCache.txt')) or { panic(err) }

if regenerate_c {
run_at('luajit ./generator.lua gcc internal glfw', os.join_path(repo_dir, 'cimgui', 'generator')) or { panic(err) }
} else {
println('Using the generated cimgui API committed by the pinned revision.')
}
include_dir := os.join_path(repo_dir, 'include')
copy_matching(os.join_path(repo_dir, 'cimgui', '*.h'), include_dir) or { panic(err) }
copy_matching(os.join_path(repo_dir, 'cimgui', '*.cpp'), include_dir) or { panic(err) }
add_translation_fix(os.join_path(include_dir, 'cimgui.h')) or { panic(err) }

if regenerate_c {
run_at('luajit ./generator.lua gcc internal glfw', os.join_path(repo_dir, 'cimplot', 'generator')) or { panic(err) }
} else {
println('Using the generated cimplot API committed by the pinned revision.')
}
copy_matching(os.join_path(repo_dir, 'cimplot', '*.h'), include_dir) or { panic(err) }
copy_matching(os.join_path(repo_dir, 'cimplot', '*.cpp'), include_dir) or { panic(err) }
add_translation_fix(os.join_path(include_dir, 'cimplot.h')) or { panic(err) }

imgui_include := os.join_path(include_dir, 'imgui') + os.path_separator
implot_include := os.join_path(include_dir, 'implot') + os.path_separator
os.mkdir_all(imgui_include)!
os.mkdir_all(implot_include)!
run_at('git checkout-index -a -f --prefix=${os.quoted_path(imgui_include)}', os.join_path(repo_dir, 'cimgui', 'imgui')) or { panic(err) }
run_at('git checkout-index -a -f --prefix=${os.quoted_path(implot_include)}', os.join_path(repo_dir, 'cimplot', 'implot')) or { panic(err) }

os.write_file(os.join_path(include_dir, 'c2v.toml'), '[project]\nadditional_flags = "${c2v_flags}"\n')!
run_at('v translate cimgui.h', include_dir) or { panic(err) }
run_at('v translate cimplot.h', include_dir) or { panic(err) }
remove_file(os.join_path(include_dir, 'cimgui.json')) or { panic(err) }
remove_file(os.join_path(include_dir, 'cimplot.json')) or { panic(err) }

imgui_binding := os.join_path(repo_dir, 'imgui.v')
implot_binding := os.join_path(repo_dir, 'implot', 'implot.v')
os.mv(os.join_path(include_dir, 'cimgui.v'), imgui_binding)!
os.mv(os.join_path(include_dir, 'cimplot.v'), implot_binding)!
cleanup := os.join_path(repo_dir, 'cleanup_imgui_implot.perl')
run_at('perl ${os.quoted_path(cleanup)} ${os.quoted_path(imgui_binding)} ${os.quoted_path(imgui_binding)} imgui', repo_dir) or { panic(err) }
run_at('perl ${os.quoted_path(cleanup)} ${os.quoted_path(implot_binding)} ${os.quoted_path(implot_binding)} implot', repo_dir) or { panic(err) }
run_at('v fmt -w ${os.quoted_path(imgui_binding)}', repo_dir) or { panic(err) }
// Do not format ImPlot: its C field/type pair `Marker Marker` is currently
// collapsed by vfmt into invalid V.
run_at('v run ${os.quoted_path(os.join_path(repo_dir, 'build_vimgui.vsh'))}', repo_dir) or {
panic(err)
}
result := os.execute(parts.join(' '))
print(result.output)
exit(result.exit_code)
}
Loading