From bcab1c79d6fe23bd0ba8520da1eecf47f406d0ff Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Wed, 6 Mar 2024 19:53:20 +0900 Subject: [PATCH 1/5] Adapt to Clang's ElaboratedType sugaring changes ref: https://reviews.llvm.org/D112374 Co-Authored-By: James Wrigley --- src/Clang.jl | 2 +- src/generator/jltypes.jl | 6 +----- src/generator/nested.jl | 2 +- src/generator/resolve_deps.jl | 6 +++--- src/generator/system_deps.jl | 6 +++--- src/generator/top_level.jl | 2 +- src/type.jl | 25 +++++++++++++++++++++++++ 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/Clang.jl b/src/Clang.jl index a4132f49..82e3a691 100644 --- a/src/Clang.jl +++ b/src/Clang.jl @@ -45,7 +45,7 @@ export is_typedef_anon, is_forward_declaration, is_inclusion_directive export search, children include("type.jl") -export has_elaborated_reference, get_elaborated_cursor +export has_elaborated_reference, has_elaborated_tag_reference, get_elaborated_cursor export has_function_reference export fields diff --git a/src/generator/jltypes.jl b/src/generator/jltypes.jl index 4b7fc616..b541f92e 100644 --- a/src/generator/jltypes.jl +++ b/src/generator/jltypes.jl @@ -146,11 +146,7 @@ tojulia(x::CLFloat16) = JuliaCfloat16() # Float16 tojulia(x::CLNullPtr) = JuliaUnknown(x) # C++11 nullptr tojulia(x::CLPointer) = JuliaCpointer(x) tojulia(x::CLBlockPointer) = JuliaUnknown(x) # ObjectveC's block pointer -function tojulia(x::CLElaborated) - jlty = tojulia(getNamedType(x)) - @assert jlty isa JuliaCenum || jlty isa JuliaCrecord - return jlty -end +tojulia(x::CLElaborated) = tojulia(getNamedType(x)) tojulia(x::CLInvalid) = JuliaUnknown(x) tojulia(x::CLFunctionProto) = JuliaCfunction(spelling(getTypeDeclaration(x))) tojulia(x::CLFunctionNoProto) = JuliaCfunction(spelling(getTypeDeclaration(x))) diff --git a/src/generator/nested.jl b/src/generator/nested.jl index 281b9097..65fe2d4c 100644 --- a/src/generator/nested.jl +++ b/src/generator/nested.jl @@ -4,7 +4,7 @@ function collect_nested_record!(dag::ExprDAG, node::ExprNode, new_tags, isdeterm field_cursors = isempty(field_cursors) ? children(node.cursor) : field_cursors for field_cursor in field_cursors field_ty = getCursorType(field_cursor) - has_elaborated_reference(field_ty) || continue + has_elaborated_tag_reference(field_ty) || continue field_jlty = tojulia(field_ty) leaf_jlty = get_jl_leaf_type(field_jlty) leaf_jlty isa JuliaCrecord || continue # nested enums are not legal in C diff --git a/src/generator/resolve_deps.jl b/src/generator/resolve_deps.jl index cf6a2a74..54c0f06d 100644 --- a/src/generator/resolve_deps.jl +++ b/src/generator/resolve_deps.jl @@ -21,7 +21,7 @@ function resolve_dependency!(dag::ExprDAG, node::ExprNode{FunctionProto}, option # do nothing for unknowns since we just skip them in the downstream passes is_jl_unknown(leaf_ty) && return dag - hasref = has_elaborated_reference(ty) + hasref = has_elaborated_tag_reference(ty) if hasref && haskey(dag.tags, leaf_ty.sym) push!(node.adj, dag.tags[leaf_ty.sym]) elseif !hasref && haskey(dag.ids, leaf_ty.sym) @@ -59,7 +59,7 @@ function resolve_dependency!(dag::ExprDAG, node::ExprNode{FunctionNoProto}, opti is_jl_basic(leaf_ty) && return dag - hasref = has_elaborated_reference(ty) + hasref = has_elaborated_tag_reference(ty) if hasref && haskey(dag.tags, leaf_ty.sym) push!(node.adj, dag.tags[leaf_ty.sym]) elseif !hasref && haskey(dag.ids, leaf_ty.sym) @@ -145,7 +145,7 @@ function resolve_dependency!(dag::ExprDAG, node::ExprNode{<:AbstractStructNodeTy is_jl_basic(leaf_ty) && continue - hasref = has_elaborated_reference(ty) + hasref = has_elaborated_tag_reference(ty) if hasref && haskey(dag.tags, leaf_ty.sym) push!(node.adj, dag.tags[leaf_ty.sym]) elseif !hasref && haskey(dag.ids, leaf_ty.sym) diff --git a/src/generator/system_deps.jl b/src/generator/system_deps.jl index d007b158..33fbc87b 100644 --- a/src/generator/system_deps.jl +++ b/src/generator/system_deps.jl @@ -23,7 +23,7 @@ function collect_dependent_system_nodes!(dag::ExprDAG, node::ExprNode{FunctionPr # FIXME: typedef func proto - hasref = has_elaborated_reference(ty) + hasref = has_elaborated_tag_reference(ty) if (hasref && haskey(dag.tags, leaf_ty.sym)) || (!hasref && haskey(dag.ids, leaf_ty.sym)) || haskey(dag.ids_extra, leaf_ty.sym) || @@ -50,7 +50,7 @@ function collect_dependent_system_nodes!(dag::ExprDAG, node::ExprNode{FunctionNo is_jl_basic(leaf_ty) && return system_nodes - hasref = has_elaborated_reference(ty) + hasref = has_elaborated_tag_reference(ty) if (hasref && haskey(dag.tags, leaf_ty.sym)) || (!hasref && haskey(dag.ids, leaf_ty.sym)) || haskey(dag.ids_extra, leaf_ty.sym) @@ -134,7 +134,7 @@ function collect_dependent_system_nodes!(dag::ExprDAG, type::CLType, system_node # FIXME: typedef func proto - hasref = has_elaborated_reference(ty) + hasref = has_elaborated_tag_reference(ty) if (hasref && haskey(dag.tags, leaf_ty.sym)) || (!hasref && haskey(dag.ids, leaf_ty.sym)) || haskey(dag.ids_extra, leaf_ty.sym) || diff --git a/src/generator/top_level.jl b/src/generator/top_level.jl index 840bd758..ab921a3d 100644 --- a/src/generator/top_level.jl +++ b/src/generator/top_level.jl @@ -37,7 +37,7 @@ end function collect_top_level_nodes!(nodes::Vector{ExprNode}, cursor::CLTypedefDecl, options) lhs_type = getTypedefDeclUnderlyingType(cursor) - if has_elaborated_reference(lhs_type) + if has_elaborated_tag_reference(lhs_type) ty = TypedefElaborated() elseif has_function_reference(lhs_type) ty = TypedefFunction() diff --git a/src/type.jl b/src/type.jl index edf9f2b1..95fa5e28 100644 --- a/src/type.jl +++ b/src/type.jl @@ -286,6 +286,31 @@ function has_elaborated_reference(ty::CXType) end has_elaborated_reference(ty::CLType) = has_elaborated_reference(ty.type) + +""" + has_elaborated_tag_reference(ty::CLType) -> Bool + has_elaborated_tag_reference(ty::CXType) -> Bool +Return true if the type is an elaborated tag type or the type indirectly refers to an +elaborated tag type. +""" +function has_elaborated_tag_reference(ty::CXType) + if kind(ty) == CXType_Pointer + ptreety = getPointeeType(ty) + return has_elaborated_tag_reference(ptreety) + elseif kind(ty) == CXType_ConstantArray || kind(ty) == CXType_IncompleteArray + elty = getElementType(ty) + return has_elaborated_tag_reference(elty) + elseif is_elaborated(ty) + nty = getNamedType(ty) + return kind(nty) == CXType_Enum || kind(nty) == CXType_Record + else + return false + end +end +has_elaborated_tag_reference(ty::CLType) = has_elaborated_tag_reference(ty.type) + + + """ get_elaborated_cursor(ty::CLType) -> CLCursor get_elaborated_cursor(ty::CXType) -> CXCursor From 7a705df45d017066cace5ad3c7946f8a6898d644 Mon Sep 17 00:00:00 2001 From: Gnimuc Date: Wed, 6 Mar 2024 20:29:29 +0900 Subject: [PATCH 2/5] fix-up --- src/type.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/type.jl b/src/type.jl index 95fa5e28..20613dcd 100644 --- a/src/type.jl +++ b/src/type.jl @@ -302,7 +302,11 @@ function has_elaborated_tag_reference(ty::CXType) return has_elaborated_tag_reference(elty) elseif is_elaborated(ty) nty = getNamedType(ty) - return kind(nty) == CXType_Enum || kind(nty) == CXType_Record + if kind(nty) == CXType_Enum || kind(nty) == CXType_Record + return true + else + return has_elaborated_tag_reference(nty) + end else return false end From 1e14d502dde8c3b51fb61fa1e96d305a31e229a7 Mon Sep 17 00:00:00 2001 From: JamesWrigley Date: Tue, 5 Mar 2024 00:06:49 +0100 Subject: [PATCH 3/5] Generate bindings in a cd() do-block This makes it a little easier to use from different directories. --- gen/generator.jl | 75 ++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/gen/generator.jl b/gen/generator.jl index 38fbefbd..f2aa77ab 100644 --- a/gen/generator.jl +++ b/gen/generator.jl @@ -1,7 +1,6 @@ using Clang.Generators using Clang.LibClang.Clang_jll -cd(@__DIR__) options = load_options(joinpath(@__DIR__, "generator.toml")) @@ -58,42 +57,44 @@ const dependencies = PkgSpec[PkgSpec(; name = "LLVM_full_jll")] const libdir = joinpath(@__DIR__, "..", "lib") -for (llvm_version, julia_version) in (#=(v"12.0.1", v"1.7"),=# - (v"13.0.1", v"1.8"), - (v"14.0.5", v"1.9"), - (v"15.0.6", v"1.10"), - (v"16.0.6", v"1.11")) - @info "Generating..." llvm_version julia_version - temp_prefix() do prefix - # let prefix = Prefix(mktempdir()) - platform = Pkg.BinaryPlatforms.HostPlatform() - platform["llvm_version"] = string(llvm_version.major) - platform["julia_version"] = string(julia_version) - artifact_paths = setup_dependencies(prefix, dependencies, platform; verbose=true) - - let options = deepcopy(options) - options["general"]["callback_documentation"] = get_docs - output_file_path = joinpath(libdir, string(llvm_version.major), options["general"]["output_file_path"]) - isdir(dirname(output_file_path)) || mkpath(dirname(output_file_path)) - options["general"]["output_file_path"] = output_file_path - - include_dir = joinpath(destdir(prefix, platform), "include") - libclang_header_dir = joinpath(include_dir, "clang-c") - args = Generators.get_default_args() - push!(args, "-I$include_dir") - - headers = detect_headers(libclang_header_dir, args) - ctx = create_context(headers, args, options) - - # build without printing so we can do custom rewriting - build!(ctx, BUILDSTAGE_NO_PRINTING) - - rewrite!(ctx.dag) - - # print - build!(ctx, BUILDSTAGE_PRINTING_ONLY) +cd(@__DIR__) do + for (llvm_version, julia_version) in (#=(v"12.0.1", v"1.7"),=# + (v"13.0.1", v"1.8"), + (v"14.0.5", v"1.9"), + (v"15.0.6", v"1.10"), + (v"16.0.6", v"1.11")) + @info "Generating..." llvm_version julia_version + temp_prefix() do prefix + # let prefix = Prefix(mktempdir()) + platform = Pkg.BinaryPlatforms.HostPlatform() + platform["llvm_version"] = string(llvm_version.major) + platform["julia_version"] = string(julia_version) + artifact_paths = setup_dependencies(prefix, dependencies, platform; verbose=true) + + let options = deepcopy(options) + options["general"]["callback_documentation"] = get_docs + output_file_path = joinpath(libdir, string(llvm_version.major), options["general"]["output_file_path"]) + isdir(dirname(output_file_path)) || mkpath(dirname(output_file_path)) + options["general"]["output_file_path"] = output_file_path + + include_dir = joinpath(destdir(prefix, platform), "include") + libclang_header_dir = joinpath(include_dir, "clang-c") + args = Generators.get_default_args() + push!(args, "-I$include_dir") + + headers = detect_headers(libclang_header_dir, args) + ctx = create_context(headers, args, options) + + # build without printing so we can do custom rewriting + build!(ctx, BUILDSTAGE_NO_PRINTING) + + rewrite!(ctx.dag) + + # print + build!(ctx, BUILDSTAGE_PRINTING_ONLY) + end + + cleanup_dependencies(prefix, artifact_paths, platform) end - - cleanup_dependencies(prefix, artifact_paths, platform) end end From 5962e7c9aff8c33626701a9579465dd9a16d3e3d Mon Sep 17 00:00:00 2001 From: JamesWrigley Date: Tue, 5 Mar 2024 00:07:53 +0100 Subject: [PATCH 4/5] Update bindings --- lib/16/LibClang.jl | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/16/LibClang.jl b/lib/16/LibClang.jl index 820e61fc..29ee3892 100644 --- a/lib/16/LibClang.jl +++ b/lib/16/LibClang.jl @@ -4330,6 +4330,19 @@ function clang_visitChildren(parent, visitor, client_data) @ccall libclang.clang_visitChildren(parent::CXCursor, visitor::CXCursorVisitor, client_data::CXClientData)::Cuint end +mutable struct _CXChildVisitResult end + +const CXCursorVisitorBlock = Ptr{_CXChildVisitResult} + +""" + clang_visitChildrenWithBlock(parent, block) + +Visits the children of a cursor using the specified block. Behaves identically to [`clang_visitChildren`](@ref)() in all other respects. +""" +function clang_visitChildrenWithBlock(parent, block) + @ccall libclang.clang_visitChildrenWithBlock(parent::CXCursor, block::CXCursorVisitorBlock)::Cuint +end + """ clang_getCursorUSR(arg1) @@ -6086,6 +6099,18 @@ function clang_findIncludesInFile(TU, file, visitor) @ccall libclang.clang_findIncludesInFile(TU::CXTranslationUnit, file::CXFile, visitor::CXCursorAndRangeVisitor)::CXResult end +mutable struct _CXCursorAndRangeVisitorBlock end + +const CXCursorAndRangeVisitorBlock = Ptr{_CXCursorAndRangeVisitorBlock} + +function clang_findReferencesInFileWithBlock(arg1, arg2, arg3) + @ccall libclang.clang_findReferencesInFileWithBlock(arg1::CXCursor, arg2::CXFile, arg3::CXCursorAndRangeVisitorBlock)::CXResult +end + +function clang_findIncludesInFileWithBlock(arg1, arg2, arg3) + @ccall libclang.clang_findIncludesInFileWithBlock(arg1::CXTranslationUnit, arg2::CXFile, arg3::CXCursorAndRangeVisitorBlock)::CXResult +end + """ The client's data object that is associated with a [`CXFile`](@ref). """ From 08b1ad2460d837e43e987a2e69990030a51d1f6f Mon Sep 17 00:00:00 2001 From: JamesWrigley Date: Wed, 6 Mar 2024 14:20:01 +0100 Subject: [PATCH 5/5] Load the REPL module in the tests so we can use @docs See: https://github.com/JuliaLang/julia/issues/52986 --- test/Project.toml | 1 + test/runtests.jl | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/test/Project.toml b/test/Project.toml index e8b41533..dbd6c374 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -3,6 +3,7 @@ BinaryBuilder = "12aac903-9f7c-5d81-afc2-d9565ea332ae" CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82" CMake_jll = "3f4e10e2-61f2-5801-8945-23b9d642d0e6" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" Tar = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" diff --git a/test/runtests.jl b/test/runtests.jl index db6213b0..53aded9f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,6 +1,10 @@ using Clang using Test +# Temporary hack to make @doc work in 1.11 for the documentation tests. See: +# https://github.com/JuliaLang/julia/issues/52986 +using REPL + include("generators.jl") include("test_mpi.jl")