-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
More Symbol Exports and C-API Example #4997
Merged
Merged
Changes from 1 commit
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
JULIAHOME = $(abspath ..) | ||
include $(JULIAHOME)/Make.inc | ||
|
||
override CFLAGS += $(JCFLAGS) | ||
override CXXFLAGS += $(JCXXFLAGS) | ||
|
||
FLAGS = -Wall -Wno-strict-aliasing -fno-omit-frame-pointer \ | ||
-I$(JULIAHOME)/src -I$(JULIAHOME)/src/support -I$(BUILD)/include $(CFLAGS) | ||
|
||
DEBUGFLAGS += $(FLAGS) | ||
SHIPFLAGS += $(FLAGS) | ||
JLDFLAGS += $(LDFLAGS) $(NO_WHOLE_ARCHIVE) $(call exec,$(LLVM_CONFIG) --ldflags) $(OSLIBS) $(RPATH) | ||
|
||
ifeq ($(USE_SYSTEM_LIBM),0) | ||
ifneq ($(UNTRUSTED_SYSTEM_LIBM),0) | ||
ifeq ($(OS),WINNT) | ||
JLDFLAGS += $(WHOLE_ARCHIVE) $(BUILD)/lib/libopenlibm.a $(NO_WHOLE_ARCHIVE) | ||
else | ||
JLDFLAGS += $(WHOLE_ARCHIVE) $(BUILD)/$(JL_LIBDIR)/libopenlibm.a $(NO_WHOLE_ARCHIVE) | ||
endif | ||
endif | ||
endif | ||
|
||
embedding-release: embedding | ||
|
||
release debug: | ||
$(MAKE) embedding-$@ | ||
|
||
%.o: %.c | ||
@$(call PRINT_CC, $(CC) $(CPPFLAGS) $(CFLAGS) $(SHIPFLAGS) -c $< -o $@) | ||
%.do: %.c | ||
@$(call PRINT_CC, $(CC) $(CPPFLAGS) $(CFLAGS) $(DEBUGFLAGS) -c $< -o $@) | ||
|
||
embedding: $(BUILD)/bin/embedding$(EXE) | ||
embedding-debug: $(BUILD)/bin/embedding-debug$(EXE) | ||
|
||
$(BUILD)/bin/embedding$(EXE): embedding.o | ||
@$(call PRINT_LINK, $(CXX) $(LINK_FLAGS) $(SHIPFLAGS) $^ -o $@ -L$(BUILD)/$(JL_PRIVATE_LIBDIR) -L$(BUILD)/$(JL_LIBDIR) -ljulia $(JLDFLAGS)) | ||
$(BUILD)/bin/embedding-debug$(EXE): embedding.do | ||
@$(call PRINT_LINK, $(CXX) $(LINK_FLAGS) $(DEBUGFLAGS) $^ -o $@ -L$(BUILD)/$(JL_PRIVATE_LIBDIR) -L$(BUILD)/$(JL_LIBDIR) -ljulia-debug $(JLDFLAGS)) | ||
|
||
|
||
clean: | $(CLEAN_TARGETS) | ||
rm -f *.o *.do | ||
rm -f $(BUILD)/bin/embedding-debug $(BUILD)/bin/embedding | ||
|
||
.PHONY: clean release debug | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#include <julia.h> | ||
#include <stdio.h> | ||
#include <math.h> | ||
|
||
double my_c_sqrt(double x) | ||
{ | ||
return sqrt(x); | ||
} | ||
|
||
int main() | ||
{ | ||
jl_init(NULL); | ||
|
||
{ | ||
// Simple running Julia code | ||
|
||
jl_eval_string("println(sqrt(2.0))"); | ||
} | ||
|
||
{ | ||
// Accessing the return value | ||
|
||
jl_value_t *ret = jl_eval_string("sqrt(2.0)"); | ||
|
||
if(jl_is_float64(ret)) | ||
{ | ||
double retDouble = jl_unbox_float64(ret); | ||
printf("sqrt(2.0) in C: %e\n", retDouble); | ||
} | ||
} | ||
|
||
{ | ||
// Same as above but with function handle (more flexible) | ||
|
||
jl_function_t *func = jl_get_function(jl_base_module, "sqrt"); | ||
jl_value_t* argument = jl_box_float64(2.0); | ||
jl_value_t* ret = jl_call1(func, argument); | ||
|
||
if(jl_is_float64(ret)) | ||
{ | ||
double retDouble = jl_unbox_float64(ret); | ||
printf("sqrt(2.0) in C: %e\n", retDouble); | ||
} | ||
} | ||
|
||
{ | ||
// 1D arrays | ||
|
||
jl_value_t* array_type = jl_apply_array_type( jl_float64_type, 1 ); | ||
jl_array_t* x = jl_alloc_array_1d(array_type , 10); | ||
JL_GC_PUSH1(&x); | ||
|
||
double* xData = jl_array_data(x); | ||
|
||
for(size_t i=0; i<jl_array_len(x); i++) | ||
xData[i] = i; | ||
|
||
jl_function_t *func = jl_get_function(jl_base_module, "reverse!"); | ||
jl_call1(func, (jl_value_t*) x); | ||
|
||
printf("x = ["); | ||
for(size_t i=0; i<jl_array_len(x); i++) | ||
printf("%e ", xData[i]); | ||
printf("]\n"); | ||
|
||
JL_GC_POP(); | ||
} | ||
|
||
{ | ||
// define julia function and call it | ||
|
||
jl_eval_string("my_func(x) = 2*x"); | ||
|
||
jl_function_t *func = jl_get_function(jl_current_module, "my_func"); | ||
jl_value_t* arg = jl_box_float64(5.0); | ||
double ret = jl_unbox_float64(jl_call1(func, arg)); | ||
|
||
printf("my_func(5.0) = %f\n", ret); | ||
} | ||
|
||
{ | ||
// call c function | ||
|
||
jl_eval_string("println( ccall( :my_c_sqrt, Float64, (Float64,), 2.0 ) )"); | ||
} | ||
|
||
{ | ||
// check for exceptions | ||
|
||
jl_eval_string("this_function_does_not_exist()"); | ||
|
||
if (jl_exception_occurred()) | ||
printf("%s \n", jl_get_exception_str( jl_exception_occurred() ) ); | ||
} | ||
|
||
|
||
return 0; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -366,7 +366,7 @@ extern jl_datatype_t *jl_function_type; | |
extern jl_datatype_t *jl_abstractarray_type; | ||
extern jl_datatype_t *jl_storedarray_type; | ||
extern jl_datatype_t *jl_densearray_type; | ||
extern jl_datatype_t *jl_array_type; | ||
extern DLLEXPORT jl_datatype_t *jl_array_type; | ||
extern jl_typename_t *jl_array_typename; | ||
extern jl_datatype_t *jl_weakref_type; | ||
extern DLLEXPORT jl_datatype_t *jl_ascii_string_type; | ||
|
@@ -390,18 +390,18 @@ extern jl_datatype_t *jl_box_type; | |
extern jl_value_t *jl_box_any_type; | ||
extern jl_typename_t *jl_box_typename; | ||
|
||
extern jl_datatype_t *jl_bool_type; | ||
extern jl_datatype_t *jl_char_type; | ||
extern jl_datatype_t *jl_int8_type; | ||
extern jl_datatype_t *jl_uint8_type; | ||
extern jl_datatype_t *jl_int16_type; | ||
extern jl_datatype_t *jl_uint16_type; | ||
extern jl_datatype_t *jl_int32_type; | ||
extern jl_datatype_t *jl_uint32_type; | ||
extern jl_datatype_t *jl_int64_type; | ||
extern jl_datatype_t *jl_uint64_type; | ||
extern jl_datatype_t *jl_float32_type; | ||
extern jl_datatype_t *jl_float64_type; | ||
extern DLLEXPORT jl_datatype_t *jl_bool_type; | ||
extern DLLEXPORT jl_datatype_t *jl_char_type; | ||
extern DLLEXPORT jl_datatype_t *jl_int8_type; | ||
extern DLLEXPORT jl_datatype_t *jl_uint8_type; | ||
extern DLLEXPORT jl_datatype_t *jl_int16_type; | ||
extern DLLEXPORT jl_datatype_t *jl_uint16_type; | ||
extern DLLEXPORT jl_datatype_t *jl_int32_type; | ||
extern DLLEXPORT jl_datatype_t *jl_uint32_type; | ||
extern DLLEXPORT jl_datatype_t *jl_int64_type; | ||
extern DLLEXPORT jl_datatype_t *jl_uint64_type; | ||
extern DLLEXPORT jl_datatype_t *jl_float32_type; | ||
extern DLLEXPORT jl_datatype_t *jl_float64_type; | ||
extern jl_datatype_t *jl_floatingpoint_type; | ||
extern jl_datatype_t *jl_voidpointer_type; | ||
extern jl_datatype_t *jl_pointer_type; | ||
|
@@ -684,7 +684,7 @@ int jl_args_morespecific(jl_value_t *a, jl_value_t *b); | |
jl_typename_t *jl_new_typename(jl_sym_t *name); | ||
jl_tvar_t *jl_new_typevar(jl_sym_t *name,jl_value_t *lb,jl_value_t *ub); | ||
jl_typector_t *jl_new_type_ctor(jl_tuple_t *params, jl_value_t *body); | ||
jl_value_t *jl_apply_type(jl_value_t *tc, jl_tuple_t *params); | ||
DLLEXPORT jl_value_t *jl_apply_type(jl_value_t *tc, jl_tuple_t *params); | ||
jl_value_t *jl_apply_type_(jl_value_t *tc, jl_value_t **params, size_t n); | ||
jl_value_t *jl_instantiate_type_with(jl_value_t *t, jl_value_t **env, size_t n); | ||
jl_uniontype_t *jl_new_uniontype(jl_tuple_t *types); | ||
|
@@ -710,12 +710,12 @@ DLLEXPORT jl_function_t *jl_new_closure(jl_fptr_t proc, jl_value_t *env, | |
jl_lambda_info_t *li); | ||
DLLEXPORT jl_lambda_info_t *jl_new_lambda_info(jl_value_t *ast, jl_tuple_t *sparams); | ||
DLLEXPORT jl_tuple_t *jl_tuple(size_t n, ...); | ||
jl_tuple_t *jl_tuple1(void *a); | ||
jl_tuple_t *jl_tuple2(void *a, void *b); | ||
DLLEXPORT jl_tuple_t *jl_tuple1(void *a); | ||
DLLEXPORT jl_tuple_t *jl_tuple2(void *a, void *b); | ||
DLLEXPORT jl_tuple_t *jl_alloc_tuple(size_t n); | ||
jl_tuple_t *jl_alloc_tuple_uninit(size_t n); | ||
jl_tuple_t *jl_tuple_append(jl_tuple_t *a, jl_tuple_t *b); | ||
jl_tuple_t *jl_tuple_fill(size_t n, jl_value_t *v); | ||
DLLEXPORT jl_tuple_t *jl_tuple_append(jl_tuple_t *a, jl_tuple_t *b); | ||
DLLEXPORT jl_tuple_t *jl_tuple_fill(size_t n, jl_value_t *v); | ||
DLLEXPORT jl_sym_t *jl_symbol(const char *str); | ||
DLLEXPORT jl_sym_t *jl_symbol_lookup(const char *str); | ||
DLLEXPORT jl_sym_t *jl_symbol_n(const char *str, int32_t len); | ||
|
@@ -815,6 +815,10 @@ DLLEXPORT void jl_array_del_beg(jl_array_t *a, size_t dec); | |
DLLEXPORT void jl_array_sizehint(jl_array_t *a, size_t sz); | ||
DLLEXPORT void *jl_value_ptr(jl_value_t *a); | ||
DLLEXPORT void jl_cell_1d_push(jl_array_t *a, jl_value_t *item); | ||
STATIC_INLINE jl_value_t *jl_apply_array_type(jl_datatype_t *type, size_t dim) | ||
{ | ||
return jl_apply_type((jl_value_t*)jl_array_type, jl_tuple2(type, jl_box_long(dim))); | ||
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. Here the result of |
||
} | ||
|
||
// eq hash tables | ||
DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val); | ||
|
@@ -876,17 +880,26 @@ DLLEXPORT struct tm* localtime_r(const time_t *t, struct tm *tm); | |
// exceptions | ||
DLLEXPORT void NORETURN jl_error(const char *str); | ||
void NORETURN jl_errorf(const char *fmt, ...); | ||
void jl_too_few_args(const char *fname, int min); | ||
void jl_too_many_args(const char *fname, int max); | ||
void jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got); | ||
DLLEXPORT void jl_too_few_args(const char *fname, int min); | ||
DLLEXPORT void jl_too_many_args(const char *fname, int max); | ||
DLLEXPORT void jl_type_error(const char *fname, jl_value_t *expected, jl_value_t *got); | ||
DLLEXPORT void jl_type_error_rt(const char *fname, const char *context, | ||
jl_value_t *ty, jl_value_t *got); | ||
jl_value_t *jl_no_method_error(jl_function_t *f, jl_value_t **args, size_t na); | ||
void jl_check_type_tuple(jl_tuple_t *t, jl_sym_t *name, const char *ctx); | ||
DLLEXPORT jl_value_t *jl_exception_occurred(void); | ||
DLLEXPORT void jl_exception_clear(void); | ||
STATIC_INLINE char* jl_get_exception_str(jl_value_t* exception) | ||
{ | ||
return jl_string_data( jl_fieldref( exception ,0 ) ); | ||
} | ||
|
||
|
||
// initialization functions | ||
|
||
DLLEXPORT void julia_init(char *imageFile, int build_mode); | ||
DLLEXPORT int julia_trampoline(int argc, char *argv[], int (*pmain)(int ac,char *av[]), char* build_mode); | ||
DLLEXPORT void jl_init(char *julia_home_dir); | ||
void jl_init_types(void); | ||
void jl_init_box_caches(void); | ||
DLLEXPORT void jl_init_frontend(void); | ||
|
@@ -911,6 +924,7 @@ jl_value_t *jl_parse_next(void); | |
DLLEXPORT jl_value_t *jl_load_file_string(const char *text, char *filename); | ||
DLLEXPORT jl_value_t *jl_expand(jl_value_t *expr); | ||
jl_lambda_info_t *jl_wrap_expr(jl_value_t *expr); | ||
DLLEXPORT void *jl_eval_string(char *str); | ||
|
||
// some useful functions | ||
DLLEXPORT void jl_show(jl_value_t *stream, jl_value_t *v); | ||
|
@@ -926,7 +940,7 @@ extern DLLEXPORT jl_module_t *jl_main_module; | |
extern DLLEXPORT jl_module_t *jl_core_module; | ||
extern DLLEXPORT jl_module_t *jl_base_module; | ||
extern DLLEXPORT jl_module_t *jl_current_module; | ||
jl_module_t *jl_new_module(jl_sym_t *name); | ||
DLLEXPORT jl_module_t *jl_new_module(jl_sym_t *name); | ||
// get binding for reading | ||
DLLEXPORT jl_binding_t *jl_get_binding(jl_module_t *m, jl_sym_t *var); | ||
// get binding for assignment | ||
|
@@ -941,12 +955,16 @@ DLLEXPORT void jl_set_global(jl_module_t *m, jl_sym_t *var, jl_value_t *val); | |
DLLEXPORT void jl_set_const(jl_module_t *m, jl_sym_t *var, jl_value_t *val); | ||
DLLEXPORT void jl_checked_assignment(jl_binding_t *b, jl_value_t *rhs); | ||
DLLEXPORT void jl_declare_constant(jl_binding_t *b); | ||
void jl_module_using(jl_module_t *to, jl_module_t *from); | ||
void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s); | ||
void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s); | ||
void jl_module_importall(jl_module_t *to, jl_module_t *from); | ||
DLLEXPORT void jl_module_using(jl_module_t *to, jl_module_t *from); | ||
DLLEXPORT void jl_module_use(jl_module_t *to, jl_module_t *from, jl_sym_t *s); | ||
DLLEXPORT void jl_module_import(jl_module_t *to, jl_module_t *from, jl_sym_t *s); | ||
DLLEXPORT void jl_module_importall(jl_module_t *to, jl_module_t *from); | ||
DLLEXPORT void jl_module_export(jl_module_t *from, jl_sym_t *s); | ||
void jl_add_standard_imports(jl_module_t *m); | ||
STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name) | ||
{ | ||
return (jl_function_t*) jl_get_global(m, jl_symbol(name)); | ||
} | ||
|
||
// external libraries | ||
enum JL_RTLD_CONSTANT { | ||
|
@@ -1045,6 +1063,12 @@ jl_value_t *jl_apply(jl_function_t *f, jl_value_t **args, uint32_t nargs) | |
return f->fptr((jl_value_t*)f, args, nargs); | ||
} | ||
|
||
DLLEXPORT jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs); | ||
DLLEXPORT jl_value_t *jl_call0(jl_function_t *f); | ||
DLLEXPORT jl_value_t *jl_call1(jl_function_t *f, jl_value_t *a); | ||
DLLEXPORT jl_value_t *jl_call2(jl_function_t *f, jl_value_t *a, jl_value_t *b); | ||
DLLEXPORT jl_value_t *jl_call3(jl_function_t *f, jl_value_t *a, jl_value_t *b, jl_value_t *c); | ||
|
||
#define JL_NARGS(fname, min, max) \ | ||
if (nargs < min) jl_too_few_args(#fname, min); \ | ||
else if (nargs > max) jl_too_many_args(#fname, max); | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
These functions are convenient, but there are not many cases where you can use them correctly, since as new arguments to
f
are evaluated, the previous arguments already have to be rooted, so the extra roots allocated here are usually redundant.For example a call like
jl_call2(f, new_thing1(), new_thing2())
is buggy. I know you didn't introduce these functions, but we need to think about whether it's a good idea to keep them.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.
@JeffBezanson: Not totally sure about this. In the case
jl_call2(f, new_thing1(), new_thing2())
the arguments of thenew_thing1/2
functions have to be rooted before. But the returned values not, or? How can they when they are part of thejl_call2
call...But anyway. I can change this if you want. I just completed the
jl_call
functions that were already there. In the documentation there is currently no mention thatjl_call
will root the argumentsThere 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.
That's exactly the problem --- if you pass computed values directly via a C function call, you're probably missing a root. The only safe way to do this call is
This code pattern cannot be wrapped in a C function that simply accepts the values of
new_thing1()
andnew_thing2()
.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.
Not fully get that. Is the issue that
JL_PUSH123
take the address of ajl_value_t*
? I don't see a difference of your version tointernally
jl_call
just copies the argv array into a rooted array.If the issue is only with
JL_PUSH123
we could useJL_PUSH_ARGS
injl_call123
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.
argv[0] is not rooted during the execution of
new_thing2
.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.
Thanks Keno, sorry for not seeing this. So should I remove the rooting from the jl_call functions or not? Not sure if the double rooting really hurts a lot.
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 python -> julia interop uses jl_call.
(https://github.com/jakebolewski/pyjulia/blob/master/julia/core.py#L267)
Does the rooting problem still still exist if the arguments have already been computed ouside the function call?
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.
@jakebolewski made a very good point. Unless we expose the rooting mechanism in another form as a macro (so that they can be used in language bindings), it is essential that
jl_call
does root its argumentsThere 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 crucial point is that if a function takes 2 arguments, the first argument must be rooted while the second argument is computed. Therefore it would only help for
jl_call2
to root its arguments if the prior roots were released for some reason. I suppose that could happen, but what I'm really worried about is people writingjl_call2(f, jl_call1(g,a), jl_call1(g,b))
. This API makes that call seem possible.