Skip to content

Commit

Permalink
On Windows only build library with major soversion (#97)
Browse files Browse the repository at this point in the history
* On Windows only build library with major soversion

* Automatically get from Makefile the name of the library file

* Debug: verbose linker

* On Windows link to `-lblastrampoline-<MAJOR_VERSION>`

* Revert "Debug: verbose linker"

This reverts commit d9e47b9.

* Install only shared libraries in `$(binlib)`

This avoids installing a duplicate import library on Windows.
  • Loading branch information
giordano authored Jan 21, 2023
1 parent 1eb1fd3 commit d00e6ca
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 19 deletions.
13 changes: 12 additions & 1 deletion src/Make.inc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ ifneq (,$(findstring MINGW,$(OS))$(findstring MSYS,$(OS))$(findstring CYGWIN,$(O
endif

LBT_SOVERSION_MAJOR := 5
LBT_SOVERSION_MINOR := 3
LBT_SOVERSION_MINOR := 4
LBT_SOVERSION_PATCH := 0

ifeq ($(OS), WINNT)
Expand Down Expand Up @@ -112,3 +112,14 @@ endif
# Default installation location; we expect you to be overriding this
prefix ?= prefix
builddir ?= build

define newline # a literal \n


endef

# Makefile debugging trick:
# call print-VARIABLE to see the runtime value of any variable
# (hardened against any special characters appearing in the output)
print-%:
@echo '$*=$(subst ','\'',$(subst $(newline),\n,$($*)))'
24 changes: 18 additions & 6 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ endif
# Place the `.o` files into `$(builddir)`
MAIN_OBJS := $(addprefix $(builddir)/,$(MAIN_OBJS))

ifeq ($(OS),WINNT)
# On Windows only build the library with the major soversion, all other copies
# are useless and error prone.
TARGET_LIBRARIES = $(builddir)/$(LIB_MAJOR_VERSION)
else
TARGET_LIBRARIES = $(builddir)/$(LIB_MAJOR_VERSION) $(builddir)/$(LIB_FULL_VERSION) $(builddir)/libblastrampoline.$(SHLIB_EXT)
endif

$(builddir) $(builddir)/trampolines:
@mkdir -p $@

Expand All @@ -42,22 +50,26 @@ dump-trampolines: trampolines/trampolines_$(ARCH).S
$(CC) $< -S | sed -E 's/ ((%%)|;) /\n/g' | sed -E 's/.global/\n.global/g'


$(builddir)/$(LIB_FULL_VERSION): $(MAIN_OBJS)
@$(call PRINT_CC,$(CC) -o "$@" $(call IMPLIB_FLAGS,$(builddir)/$(LIB_MAJOR_VERSION)) $(LBT_CFLAGS) $(SONAME_FLAG) $^ -shared $(LBT_LDFLAGS))
$(builddir)/$(LIB_MAJOR_VERSION): $(MAIN_OBJS)
@$(call PRINT_CC,$(CC) -o "$@" $(call IMPLIB_FLAGS,$@) $(LBT_CFLAGS) $(SONAME_FLAG) $^ -shared $(LBT_LDFLAGS))

$(builddir)/$(LIB_MAJOR_VERSION): | $(builddir)/$(LIB_FULL_VERSION)
ln -sf "$(LIB_FULL_VERSION)" "$@"
ifneq ($(OS),WINNT)
$(builddir)/$(LIB_FULL_VERSION): | $(builddir)/$(LIB_MAJOR_VERSION)
ln -sf "$(LIB_MAJOR_VERSION)" "$@"

$(builddir)/libblastrampoline.$(SHLIB_EXT): | $(builddir)/$(LIB_MAJOR_VERSION)
ln -sf "$(LIB_MAJOR_VERSION)" "$@"
endif

# Install both libraries and our headers
install: $(builddir)/libblastrampoline.$(SHLIB_EXT)
install: $(TARGET_LIBRARIES)
@mkdir -p $(DESTDIR)$(prefix)/include/libblastrampoline
-@cp -Ra $(LBT_ROOT)/include/* $(DESTDIR)$(prefix)/include/libblastrampoline
@cp -a $(LBT_ROOT)/src/libblastrampoline.h $(DESTDIR)$(prefix)/include/
@mkdir -p $(DESTDIR)$(prefix)/$(binlib)
@cp -a $(builddir)/libblastrampoline*$(SHLIB_EXT)* $(DESTDIR)$(prefix)/$(binlib)/
@for lib in $(TARGET_LIBRARIES); do \
cp -a $${lib} $(DESTDIR)$(prefix)/$(binlib)/; \
done
ifeq ($(OS),WINNT)
@mkdir -p $(DESTDIR)$(prefix)/lib
@cp -a $(builddir)/$(LIB_MAJOR_VERSION).a $(DESTDIR)$(prefix)/lib
Expand Down
16 changes: 8 additions & 8 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -121,28 +121,28 @@ lbt_dir = joinpath(lbt_dir, binlib)

@testset "LBT -> OpenBLAS_jll ($(openblas_interface))" begin
libdirs = unique(vcat(lbt_dir, OpenBLAS_jll.LIBPATH_list..., CompilerSupportLibraries_jll.LIBPATH_list...))
run_all_tests("blastrampoline", libdirs, openblas_interface, OpenBLAS_jll.libopenblas_path, tests=[dgemm, sgesv, sdot, zdotc])
run_all_tests(blastrampoline_link_name(), libdirs, openblas_interface, OpenBLAS_jll.libopenblas_path, tests=[dgemm, sgesv, sdot, zdotc])
end

# And again, but this time with OpenBLAS32_jll
@testset "LBT -> OpenBLAS32_jll (LP64)" begin
libdirs = unique(vcat(lbt_dir, OpenBLAS32_jll.LIBPATH_list..., CompilerSupportLibraries_jll.LIBPATH_list...))
run_all_tests("blastrampoline", libdirs, :LP64, OpenBLAS32_jll.libopenblas_path, tests=[dgemm, sgesv, sdot, zdotc])
run_all_tests(blastrampoline_link_name(), libdirs, :LP64, OpenBLAS32_jll.libopenblas_path, tests=[dgemm, sgesv, sdot, zdotc])
end

# Test against MKL_jll using `libmkl_rt`, which is :LP64 by default
if MKL_jll.is_available()
@testset "LBT -> MKL_jll (LP64)" begin
libdirs = unique(vcat(lbt_dir, MKL_jll.LIBPATH_list..., CompilerSupportLibraries_jll.LIBPATH_list...))
run_all_tests("blastrampoline", libdirs, :LP64, MKL_jll.libmkl_rt_path)
run_all_tests(blastrampoline_link_name(), libdirs, :LP64, MKL_jll.libmkl_rt_path)
end

# Test that we can set MKL's interface via an environment variable to select ILP64, and LBT detects it properly
if Sys.WORD_SIZE == 64
@testset "LBT -> MKL_jll (ILP64, via env)" begin
withenv("MKL_INTERFACE_LAYER" => "ILP64") do
libdirs = unique(vcat(lbt_dir, MKL_jll.LIBPATH_list..., CompilerSupportLibraries_jll.LIBPATH_list...))
run_all_tests("blastrampoline", libdirs, :ILP64, MKL_jll.libmkl_rt_path)
run_all_tests(blastrampoline_link_name(), libdirs, :ILP64, MKL_jll.libmkl_rt_path)
end
end
end
Expand All @@ -155,13 +155,13 @@ veclib_blas_path = "/System/Library/Frameworks/Accelerate.framework/Versions/A/F
if dlopen_e(veclib_blas_path) != C_NULL
# Test that we can run BLAS-only tests without LAPACK loaded (`sgesv` test requires LAPACK symbols)
@testset "LBT -> vecLib/libBLAS" begin
run_all_tests("blastrampoline", [lbt_dir], :LP64, veclib_blas_path; tests=[dgemm, sdot, zdotc])
run_all_tests(blastrampoline_link_name(), [lbt_dir], :LP64, veclib_blas_path; tests=[dgemm, sdot, zdotc])
end

# With LAPACK as well, run all tests except `dgemmt`
veclib_lapack_path = "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/libLAPACK.dylib"
@testset "LBT -> vecLib/libLAPACK" begin
run_all_tests("blastrampoline", [lbt_dir], :LP64, string(veclib_blas_path, ";", veclib_lapack_path), tests=[dgemm, sgesv, sdot, zdotc])
run_all_tests(blastrampoline_link_name(), [lbt_dir], :LP64, string(veclib_blas_path, ";", veclib_lapack_path), tests=[dgemm, sgesv, sdot, zdotc])
end
end

Expand All @@ -171,14 +171,14 @@ blas64 = dlopen("libblas64", throw_error=false)
if blas64 !== nothing
# Test that we can run BLAS-only tests without LAPACK loaded (`sgesv` test requires LAPACK symbols, blas64 doesn't have CBLAS)
@testset "LBT -> libblas64 (ILP64, BLAS)" begin
run_all_tests("blastrampoline", [lbt_dir], :ILP64, dlpath(blas64); tests=[dgemm, sdot])
run_all_tests(blastrampoline_link_name(), [lbt_dir], :ILP64, dlpath(blas64); tests=[dgemm, sdot])
end

# Check if we have a `liblapack` and if we do, run again, this time including `sgesv`
lapack = dlopen("liblapack64", throw_error=false)
if lapack !== nothing
@testset "LBT -> libblas64 + liblapack64 (ILP64, BLAS+LAPACK)" begin
run_all_tests("blastrampoline", [lbt_dir], :ILP64, "$(dlpath(blas64));$(dlpath(lapack))"; tests=[dgemm, sdot, sgesv])
run_all_tests(blastrampoline_link_name(), [lbt_dir], :ILP64, "$(dlpath(blas64));$(dlpath(lapack))"; tests=[dgemm, sdot, sgesv])
end
end
end
Expand Down
20 changes: 16 additions & 4 deletions test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ end

needs_m32() = startswith(last(capture_output(`$(cc) -dumpmachine`)), "x86_64") && Sys.WORD_SIZE == 32

function blastrampoline_major_version()
srcdir = joinpath(dirname(@__DIR__), "src")
return split(readchomp(`$(make) -sC $(pathesc(srcdir)) print-LIB_MAJOR_VERSION`), "=")[end]
end

function blastrampoline_link_name()
@static if Sys.iswindows()
# On Windows we need to link to `-lblastrampoline-<MAJOR_VERSION>`
return replace(splitext(blastrampoline_major_version())[begin], r"^lib" => "")
end
return "blastrampoline"
end


# Build blastrampoline into a temporary directory, and return that
blastrampoline_build_dir = nothing
Expand All @@ -64,15 +77,14 @@ function build_libblastrampoline()
cflags_add = "-Werror" * (needs_m32() ? " -m32" : "")
dir = mktempdir()
srcdir = joinpath(dirname(@__DIR__), "src")
run(`$(make) -sC $(pathesc(srcdir)) CFLAGS="$(cflags_add)" ARCH=$(Sys.ARCH) clean`)
run(`$(make) -sC $(pathesc(srcdir)) CFLAGS="$(cflags_add)" ARCH=$(Sys.ARCH) install builddir=$(pathesc(dir))/build prefix=$(pathesc(dir))/output`)

global blastrampoline_build_dir = joinpath(dir, "output")
run(`$(make) -sC $(pathesc(srcdir)) CFLAGS="$(cflags_add)" ARCH=$(Sys.ARCH) clean`)
run(`$(make) -sC $(pathesc(srcdir)) CFLAGS="$(cflags_add)" ARCH=$(Sys.ARCH) install builddir=$(pathesc(dir))/build prefix=$(pathesc(blastrampoline_build_dir))`)

# Give LBT a fake linking name so that we can test from within Julia versions that actually load LBT natively.
link_name = "blastramp-dev"
cp(
joinpath(blastrampoline_build_dir, binlib, "libblastrampoline.$(shlib_ext)"),
joinpath(blastrampoline_build_dir, binlib, blastrampoline_major_version()),
joinpath(blastrampoline_build_dir, binlib, "lib$(link_name).$(shlib_ext)"),
)
println("$(blastrampoline_build_dir)/$(binlib)")
Expand Down

0 comments on commit d00e6ca

Please sign in to comment.