Skip to content

Commit

Permalink
separate codegen/LLVM from julia runtime (#41936)
Browse files Browse the repository at this point in the history
separate libjulia-internal and libjulia-codegen

makes codegen optional via a plugin interface

Add special `@` character to `LOADER_BUILD_DEP_LIBS` and friends

This allows us to mark a library as `"special"` so that the loader
doesn't attempt to open it blindly, but rather interprets it as a list
of positional arguments, that it knows how to interpret.  We strictly
require exactly the number of special libraries, to help avoid errors in
the future as we add to this list.

Strip windows runtime symbols from the windows import library

Without stripping these symbols out of the import library, we end up with duplicate symbol definition errors.

Co-authored-by: Julian Samaroo <[email protected]>

Co-authored-by: Elliot Saba <[email protected]>
  • Loading branch information
JeffBezanson and staticfloat authored Oct 5, 2021
1 parent 153db7a commit 628209c
Show file tree
Hide file tree
Showing 66 changed files with 1,411 additions and 1,114 deletions.
20 changes: 15 additions & 5 deletions Make.inc
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,7 @@ OPENBLAS_DYNAMIC_ARCH:=0
OPENBLAS_TARGET_ARCH:=ARMV8
USE_BLAS64:=1
BINARY:=64
HAVE_SSP:=1
ifeq ($(OS),Darwin)
# Apple Chips are all at least A12Z
MCPU:=apple-a12
Expand Down Expand Up @@ -1500,6 +1501,12 @@ LIBJULIAINTERNAL_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlib
LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/libjulia-internal-debug.$(JL_MAJOR_SHLIB_EXT))
LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/libjulia-internal-debug.$(JL_MAJOR_SHLIB_EXT))

LIBJULIACODEGEN_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/libjulia-codegen.$(JL_MAJOR_SHLIB_EXT))
LIBJULIACODEGEN_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/libjulia-codegen.$(JL_MAJOR_SHLIB_EXT))

LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB := $(call dep_lib_path,$(build_libdir),$(build_shlibdir)/libjulia-codegen-debug.$(JL_MAJOR_SHLIB_EXT))
LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/libjulia-codegen-debug.$(JL_MAJOR_SHLIB_EXT))

ifeq ($(OS),WINNT)
ifeq ($(BINARY),32)
LIBGCC_NAME := libgcc_s_sjlj-1.$(SHLIB_EXT)
Expand Down Expand Up @@ -1539,16 +1546,19 @@ LIBM_INSTALL_DEPLIB := $(call dep_lib_path,$(libdir),$(private_shlibdir)/$(LIBMN
# We list:
# * libgcc_s, because FreeBSD needs to load ours, not the system one.
# * libopenlibm, because Windows has an untrustworthy libm, and we want to use ours more than theirs
# * libjulia, which must always come last.
# * libjulia-internal, which must always come second-to-last.
# * libjulia-codegen, which must always come last
#
# We need these four separate variables because:
# * debug builds must link against libjuliadebug, not libjulia
# * install time relative paths are not equal to build time relative paths (../lib vs. ../lib/julia)
# That second point will no longer be true for most deps once they are placed within Artifacts directories.
LOADER_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):$(LIBJULIAINTERNAL_BUILD_DEPLIB)
LOADER_DEBUG_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB)
LOADER_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):$(LIBJULIAINTERNAL_INSTALL_DEPLIB)
LOADER_DEBUG_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB)
# Note that we prefix `libjulia-codegen` and `libjulia-internal` with `@` to signify to the loader that it
# should not automatically dlopen() it in its loading loop.
LOADER_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_BUILD_DEPLIB):@$(LIBJULIACODEGEN_BUILD_DEPLIB):
LOADER_DEBUG_BUILD_DEP_LIBS = $(LIBGCC_BUILD_DEPLIB):$(LIBM_BUILD_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_BUILD_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_BUILD_DEPLIB):
LOADER_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_INSTALL_DEPLIB):
LOADER_DEBUG_INSTALL_DEP_LIBS = $(LIBGCC_INSTALL_DEPLIB):$(LIBM_INSTALL_DEPLIB):@$(LIBJULIAINTERNAL_DEBUG_INSTALL_DEPLIB):@$(LIBJULIACODEGEN_DEBUG_INSTALL_DEPLIB):

# Colors for make
ifndef VERBOSE
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ JL_TARGETS += julia-debug
endif

# private libraries, that are installed in $(prefix)/lib/julia
JL_PRIVATE_LIBS-0 := libccalltest libllvmcalltest libjulia-internal libblastrampoline
JL_PRIVATE_LIBS-0 := libccalltest libllvmcalltest libjulia-internal libjulia-codegen libblastrampoline
ifeq ($(BUNDLE_DEBUG_LIBS),1)
JL_PRIVATE_LIBS-0 += libjulia-internal-debug
JL_PRIVATE_LIBS-0 += libjulia-internal-debug libjulia-codegen-debug
endif
ifeq ($(USE_GPL_LIBS), 1)
JL_PRIVATE_LIBS-$(USE_SYSTEM_LIBSUITESPARSE) += libamd libbtf libcamd libccolamd libcholmod libcolamd libklu libldl librbio libspqr libsuitesparseconfig libumfpack
Expand Down
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Language changes
Compiler/Runtime improvements
-----------------------------

* The LLVM-based compiler has been separated from the run-time library into a new library,
`libjulia-codegen`. It is loaded by default, so normal usage should see no changes.
In deployments that do not need the compiler (e.g. system images where all needed code
is precompiled), this library (and its LLVM dependency) can simply be excluded ([#41936]).

Command-line option changes
---------------------------
Expand Down
40 changes: 30 additions & 10 deletions cli/jl_exports.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,57 @@ JL_EXPORTED_DATA_SYMBOLS(XX)
// Declare list of exported functions (sans type)
#define XX(name) JL_DLLEXPORT void name(void);
typedef void (anonfunc)(void);
JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX

// Define holder locations for function addresses as `const void * $(name)_addr = NULL;
#define XX(name) JL_HIDDEN anonfunc * name##_addr = NULL;
JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX

// Generate lists of function names and addresses
#define XX(name) "i" #name,
static const char *const jl_exported_func_names[] = {
JL_EXPORTED_FUNCS(XX)
static const char *const jl_runtime_exported_func_names[] = {
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
NULL
};
#undef XX

#define XX(name) #name"_impl",
static const char *const jl_codegen_exported_func_names[] = {
JL_CODEGEN_EXPORTED_FUNCS(XX)
NULL
};
#undef XX

#define XX(name) #name"_fallback",
static const char *const jl_codegen_fallback_func_names[] = {
JL_CODEGEN_EXPORTED_FUNCS(XX)
NULL
};
#undef XX

#define XX(name) &name##_addr,
static anonfunc **const jl_exported_func_addrs[] = {
JL_EXPORTED_FUNCS(XX)
static anonfunc **const jl_runtime_exported_func_addrs[] = {
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
NULL
};
static anonfunc **const jl_codegen_exported_func_addrs[] = {
JL_CODEGEN_EXPORTED_FUNCS(XX)
NULL
};
#undef XX
4 changes: 2 additions & 2 deletions cli/list_strip_symbols.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#include "jl_exported_funcs.inc"
#include "trampolines/common.h"
#define XX(x) --strip-symbol=CNAME(x)
JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
#undef XX
5 changes: 4 additions & 1 deletion cli/loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@
#include <stdint.h>

#ifdef _OS_WINDOWS_

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#else

#ifdef _OS_DARWIN_
#include <mach-o/dyld.h>
#endif
#ifdef _OS_FREEBSD_
#include <stddef.h>
#include <sys/sysctl.h>
#endif

#define _GNU_SOURCE // Need this for `dladdr()`
#include <stdio.h>
#include <stdlib.h>
Expand All @@ -44,6 +46,7 @@
#include <libgen.h>
#include <unistd.h>
#include <dlfcn.h>

#endif

// Borrow definition from `support/dtypes.h`
Expand Down
68 changes: 57 additions & 11 deletions cli/loader_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ extern "C" {
#endif

// Save DEP_LIBS to a variable that is explicitly sized for expansion
static char dep_libs[512] = DEP_LIBS;
static char dep_libs[1024] = DEP_LIBS;

JL_DLLEXPORT void jl_loader_print_stderr(const char * msg)
{
Expand All @@ -31,7 +31,7 @@ void jl_loader_print_stderr3(const char * msg1, const char * msg2, const char *
}

/* Wrapper around dlopen(), with extra relative pathing thrown in*/
static void * load_library(const char * rel_path, const char * src_dir) {
static void * load_library(const char * rel_path, const char * src_dir, int err) {
void * handle = NULL;

// See if a handle is already open to the basename
Expand Down Expand Up @@ -65,6 +65,8 @@ static void * load_library(const char * rel_path, const char * src_dir) {
#endif

if (handle == NULL) {
if (!err)
return NULL;
jl_loader_print_stderr3("ERROR: Unable to load dependent library ", path, "\n");
#if defined(_OS_WINDOWS_)
LPWSTR wmsg = TEXT("");
Expand Down Expand Up @@ -157,31 +159,75 @@ __attribute__((constructor)) void jl_load_libjulia_internal(void) {
// Pre-load libraries that libjulia-internal needs.
int deps_len = strlen(dep_libs);
char * curr_dep = &dep_libs[0];

// We keep track of "special" libraries names (ones whose name is prefixed with `@`)
// which are libraries that we want to load in some special, custom way, such as
// `libjulia-internal` or `libjulia-codegen`.
int special_idx = 0;
char * special_library_names[2] = {NULL};
while (1) {
// try to find next colon character, if we can't, escape out.
// try to find next colon character; if we can't, break out
char * colon = strchr(curr_dep, ':');
if (colon == NULL)
break;

// Chop the string at the colon, load this library.
// Chop the string at the colon so it's a valid-ending-string
*colon = '\0';
load_library(curr_dep, lib_dir);

// If this library name starts with `@`, don't open it here (but mark it as special)
if (curr_dep[0] == '@') {
if (special_idx > sizeof(special_library_names)/sizeof(char *)) {
jl_loader_print_stderr("ERROR: Too many special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
exit(1);
}
special_library_names[special_idx] = curr_dep + 1;
special_idx += 1;
} else {
load_library(curr_dep, lib_dir, 1);
}

// Skip ahead to next dependency
curr_dep = colon + 1;
}

// Last dependency is `libjulia-internal`, so load that and we're done with `dep_libs`!
libjulia_internal = load_library(curr_dep, lib_dir);
if (special_idx != sizeof(special_library_names)/sizeof(char *)) {
jl_loader_print_stderr("ERROR: Too few special library names specified, check LOADER_BUILD_DEP_LIBS and friends!\n");
exit(1);
}

// Unpack our special library names. This is why ordering of library names matters.
libjulia_internal = load_library(special_library_names[0], lib_dir, 1);
void *libjulia_codegen = load_library(special_library_names[1], lib_dir, 0);
const char * const * codegen_func_names;
if (libjulia_codegen == NULL) {
// if codegen is not available, use fallback implementation in libjulia-internal
libjulia_codegen = libjulia_internal;
codegen_func_names = jl_codegen_fallback_func_names;
}
else {
codegen_func_names = jl_codegen_exported_func_names;
}

// Once we have libjulia-internal loaded, re-export its symbols:
for (unsigned int symbol_idx=0; jl_exported_func_names[symbol_idx] != NULL; ++symbol_idx) {
void *addr = lookup_symbol(libjulia_internal, jl_exported_func_names[symbol_idx]);
for (unsigned int symbol_idx=0; jl_runtime_exported_func_names[symbol_idx] != NULL; ++symbol_idx) {
void *addr = lookup_symbol(libjulia_internal, jl_runtime_exported_func_names[symbol_idx]);
if (addr == NULL) {
jl_loader_print_stderr3("ERROR: Unable to load ", jl_runtime_exported_func_names[symbol_idx], " from libjulia-internal\n");
exit(1);
}
(*jl_runtime_exported_func_addrs[symbol_idx]) = addr;
}
// jl_options must be initialized very early, in case an embedder sets some
// values there before calling jl_init
((void (*)())jl_init_options_addr)();

for (unsigned int symbol_idx=0; codegen_func_names[symbol_idx] != NULL; ++symbol_idx) {
void *addr = lookup_symbol(libjulia_codegen, codegen_func_names[symbol_idx]);
if (addr == NULL) {
jl_loader_print_stderr3("ERROR: Unable to load ", jl_exported_func_names[symbol_idx], " from libjulia-internal\n");
jl_loader_print_stderr3("ERROR: Unable to load ", codegen_func_names[symbol_idx], " from libjulia-codegen\n");
exit(1);
}
(*jl_exported_func_addrs[symbol_idx]) = addr;
(*jl_codegen_exported_func_addrs[symbol_idx]) = addr;
}

// jl_options must be initialized very early, in case an embedder sets some
Expand Down
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_aarch64.S
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ CNAME(name)##: SEP \
br x16 SEP \
.cfi_endproc SEP \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_arm.S
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ CONCAT(.L,CNAMEADDR(name))##: ; \
.word CNAMEADDR(name)##-(CONCAT(.L,CNAME(name)) + 8); \
.cfi_endproc; \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_i686.S
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ CNAME(name)##:; \
.cfi_endproc; \
EXPORT(name); \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
3 changes: 2 additions & 1 deletion cli/trampolines/trampolines_powerpc64le.S
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ CNAME(name)##: ; \
.cfi_endproc; \
.size CNAME(name)##,.-CNAME(name)##; \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
5 changes: 3 additions & 2 deletions cli/trampolines/trampolines_x86_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ SEH_END(); \
.cfi_endproc; \
EXPORT(name); \

JL_EXPORTED_FUNCS(XX)
JL_RUNTIME_EXPORTED_FUNCS(XX)
#ifdef _OS_WINDOWS_
JL_EXPORTED_FUNCS_WIN(XX)
JL_RUNTIME_EXPORTED_FUNCS_WIN(XX)
#endif
JL_CODEGEN_EXPORTED_FUNCS(XX)
#undef XX
Loading

0 comments on commit 628209c

Please sign in to comment.