Skip to content

Commit

Permalink
Generate Julia wrappers with Clang.jl (#332)
Browse files Browse the repository at this point in the history
* Generate Julia wrappers with Clang.jl

* Don't use the wrappers in this PR

* Apply suggestions from code review

Co-authored-by: Tangi Migot <[email protected]>

---------

Co-authored-by: Tangi Migot <[email protected]>
  • Loading branch information
amontoison and tmigot authored Aug 14, 2024
1 parent d948fe5 commit fff8ac8
Show file tree
Hide file tree
Showing 7 changed files with 1,092 additions and 5 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ deps/*

docs/build
docs/site
dos/Manifest.toml
docs/Manifest.toml

gen/Manifest.toml

8 changes: 8 additions & 0 deletions gen/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[deps]
Clang = "40e3b903-d033-50b4-a0cc-940c62c95e31"
CUTEst_jll = "bb5f6f25-f23d-57fd-8f90-3ef7bad1d825"
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"

[compat]
julia = "1.6"
CUTEst_jll = "2.2.0"
9 changes: 9 additions & 0 deletions gen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Wrapping headers

This directory contains a script that can be used to automatically generate wrappers from C headers provided by CUTEst.
This is done using Clang.jl.

# Usage

Either run `julia wrapper.jl` directly, or include it and call the `main()` function.
Be sure to activate the project environment in this folder (`julia --project`), which will install `Clang.jl` and `JuliaFormatter.jl`.
12 changes: 12 additions & 0 deletions gen/cutest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[general]
use_julia_native_enum_type = true
print_using_CEnum = false
library_name = "cutest_lib_path"

[codegen]
use_julia_bool = true
always_NUL_terminated_string = false
use_ccall_macro = true

[codegen.macro]
macro_mode = "disable"
44 changes: 44 additions & 0 deletions gen/wrapper.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Script to parse CUTEst headers and generate Julia wrappers.
using CUTEst_jll
using Clang
using Clang.Generators
using JuliaFormatter

function main()

cd(@__DIR__)
include_dir = joinpath(CUTEst_jll.artifact_dir, "include")
headers = map(header -> joinpath(include_dir, header), ["cutest.h"])

options = load_options(joinpath(@__DIR__, "cutest.toml"))
options["general"]["output_file_path"] = joinpath("..", "src", "libcutest.jl")
options["general"]["output_ignorelist"] = ["integer", "real", "doublereal", "logical", "rp_", "rpc_", "ip_", "ipc_"]

args = get_default_args()
push!(args, "-I$include_dir")

ctx = create_context(headers, args, options)
build!(ctx)

path = options["general"]["output_file_path"]
code = read(path, String)
code = replace(code, "Ptr{integer}" => "Ptr{Cint}")
code = replace(code, "Ptr{doublereal}" => "Ptr{Float64}")
code = replace(code, "Ptr{real}" => "Ptr{Float32}")
code = replace(code, "Ptr{doubleCfloat}" => "Ptr{Float64}")
code = replace(code, "Ptr{logical}" => "Ptr{Bool}")
code = replace(code, "Ptr{rp_}" => "Ptr{Float64}")
code = replace(code, "Ptr{rpc_}" => "Ptr{Float64}")
code = replace(code, "Ptr{ip_}" => "Ptr{Cint}")
code = replace(code, "Ptr{ipc_}" => "Ptr{Cint}")
write(path, code)

format_file(path, YASStyle())

return nothing
end

# If we want to use the file as a script with `julia wrapper.jl`
if abspath(PROGRAM_FILE) == @__FILE__
main()
end
11 changes: 7 additions & 4 deletions src/CUTEst.jl
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ using Libdl
using NLPModels
import Libdl.dlsym

global cutest_lib_path = ""
global cutest_lib = C_NULL
include("libcutest.jl")

# Only one problem can be interfaced at any given time.
global cutest_instances = 0

Expand Down Expand Up @@ -64,7 +68,6 @@ end

const cutest_problems_path = joinpath(dirname(@__FILE__), "..", "deps", "files")
isdir(cutest_problems_path) || mkpath(cutest_problems_path)
global cutest_lib = C_NULL

function __init__()
if success(`bash -c "type gfortran"`)
Expand Down Expand Up @@ -215,8 +218,8 @@ function sifdecoder(
end
run(`mv OUTSDIF.d $outsdif`)
delete_temp_files(suffix)
global cutest_lib =
Libdl.dlopen(libname, Libdl.RTLD_NOW | Libdl.RTLD_DEEPBIND | Libdl.RTLD_GLOBAL)
global cutest_lib = Libdl.dlopen(libname, Libdl.RTLD_NOW | Libdl.RTLD_DEEPBIND | Libdl.RTLD_GLOBAL)
global cutest_lib_path = joinpath(cutest_problems_path, "$libname.$(Libdl.dlext)")
end
end
rm(outlog)
Expand Down Expand Up @@ -298,7 +301,7 @@ function CUTEstModel(
dlsym(cutest_lib, :fortran_open_),
Nothing,
(Ref{Int32}, Ptr{UInt8}, Ptr{Int32}),
funit,
[funit],
outsdif,
io_err,
)
Expand Down
Loading

0 comments on commit fff8ac8

Please sign in to comment.