Repository navigation
Add basic auditor / pipeline support for static libraries #96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
586f996
899dacd
1504a6b
09255a1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| using BinaryBuilderProducts, JLLGenerator | ||
|
|
||
| function resolve_static_libraries!(result::AuditResult, info::AuditInfo) | ||
| scan, pass_results, products = result.scan, result.pass_results, result.jll_lib_products | ||
| if isempty(scan.static_library_products) | ||
| return result | ||
| end | ||
| own_libraries = Set{Symbol}(lib.varname for lib in values(scan.library_products)) | ||
| union!(own_libraries, (slp.varname for slp in values(scan.static_library_products))) | ||
|
|
||
| # Unlike their dynamic counterparts, static libraries do not track dependency information | ||
| # so the only resolution we can do here is to (1) translate the LibraryDependency's the | ||
| # user provided explicitly, or (2) inherit the info from the dynamic audit. | ||
| # | ||
| # TODO: A proper audit would also verify that undefined symbols can be resolved as expected | ||
| # by these dependencies. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is gonna be pretty messy, because unlike the dynamic counterpart, we have no way to only check the first-order dependencies (e.g. are all Tell me you want to write a linker without telling me you want to write a linker.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah. I suspect we'll probably use the actual linker to do this test link / audit, since that's the intended use case anyway. Luckily since we are linking statically we can do that on all targets, not just the host platform. |
||
| dep_string(d::JLLLibraryDep) = d.mod === nothing ? string(d.varname) : string(d.mod, ".", d.varname) | ||
|
|
||
| function resolve(rel_path::String, dep::LibraryDependency) | ||
| jll_dep = JLLLibraryDep(dep.pkg, dep.varname) | ||
| if dep.pkg === nothing | ||
| if dep.varname ∉ own_libraries | ||
| push_result!(pass_results, "resolve_static_libraries!", :fail, rel_path, | ||
| "Dependency '$(dep.varname)' does not name any library product of this build") | ||
| end | ||
| else | ||
| dep_info = get(info.deps, dep.pkg, nothing) | ||
| if dep_info === nothing | ||
| push_result!(pass_results, "resolve_static_libraries!", :fail, rel_path, | ||
| "Dependency '$(dep_string(jll_dep))' names '$(dep.pkg)', which is not a dependency of this build") | ||
| elseif !any(lib -> lib.varname == dep.varname, dep_info.libs) | ||
| available = join(sort(unique(string(lib.varname) for lib in dep_info.libs)), ", ") | ||
| push_result!(pass_results, "resolve_static_libraries!", :fail, rel_path, | ||
| "Dependency '$(dep_string(jll_dep))' does not name a library product of '$(dep.pkg)' (it provides: $(isempty(available) ? "nothing" : available))") | ||
| end | ||
| end | ||
| return jll_dep | ||
| end | ||
| resolve(rel_path::String, deps::Vector{LibraryDependency}) = unique!(JLLLibraryDep[resolve(rel_path, dep) for dep in deps]) | ||
|
|
||
| dynamic_libs = Dict{Symbol,JLLLibraryProduct}(p.varname => p for p in products if isa(p, JLLLibraryProduct)) | ||
| for (rel_path, slp) in scan.static_library_products | ||
| shlib = get(dynamic_libs, slp.varname, nothing) | ||
| if shlib === nothing | ||
| # no corresponding dynamic library - require explicit deps | ||
| if slp.deps === nothing || slp.system_deps === nothing | ||
| push_result!(pass_results, "resolve_static_libraries!", :fail, rel_path, | ||
| "Standalone StaticLibraryProduct '$(slp.varname)' has no dynamic variant to inherit from; declare both `deps` and `system_deps` explicitly") | ||
| continue | ||
| end | ||
| deps = resolve(rel_path, slp.deps) | ||
| system_deps = unique(slp.system_deps) | ||
| else | ||
| if slp.deps === nothing | ||
| deps = unique(shlib.deps) # inherit from dynamic library | ||
| else | ||
| deps = resolve(rel_path, slp.deps) | ||
| # warn if the declared deps do not match the dynamic library | ||
| note_omissions(rel_path, "dependencies", String[ | ||
| d.mod === nothing ? string(d.varname) : "$(d.mod).$(d.varname)" | ||
| for d in setdiff(shlib.deps, deps) | ||
| ]) | ||
| end | ||
| if slp.system_deps === nothing | ||
| system_deps = unique(shlib.system_deps) # inherit from dynamic library | ||
| else | ||
| system_deps = unique(slp.system_deps) | ||
| # warn if the declared system_deps do not match the dynamic library | ||
| note_omissions(rel_path, "system dependencies", setdiff(shlib.system_deps, system_deps)) | ||
| end | ||
| end | ||
| push!(products, JLLStaticLibraryProduct(slp.varname, rel_path; deps, system_deps)) | ||
| end | ||
|
|
||
| sort!(products; by = p -> (p.varname, isa(p, JLLStaticLibraryProduct))) | ||
|
|
||
| return result | ||
| end | ||
|
|
||
| function note_omissions(rel_path::String, what::String, omitted::Vector{String}) | ||
| isempty(omitted) && return nothing | ||
| @warn("Declared $(what) of '$(rel_path)' omit $(length(omitted)) inherited from the dynamic variant: $(join(omitted, ", "))") | ||
| return nothing | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intended flow in
scan_files()is to actually determine from file contents the types of files, so I would populate a list ofstatic_librariesby looking at files with something like this:in order to build up an exhaustive list of static libraries, and then from that construct
static_product_map. This better matches the behavior of the other lists of files/products.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. I've pushed a rework, dependent on JuliaIO/ObjectFile.jl#63 and JuliaIO/ObjectFile.jl#59