-
Notifications
You must be signed in to change notification settings - Fork 171
@ccallable: Emit a header file with given name #1861
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
Conversation
Let's add a test for this? |
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.
I think this looks great.
We should add a test that calls this from C and includes the header file, to ensure that everything actually works. We can do that in a next PR.
Thanks @certik. The test is added and it works. |
@ccallable(header="_test_bindc_03_my_header.h") | ||
def test_emit_header_ccallable() -> i32: | ||
i: i32 = 5 | ||
assert i == 5 | ||
i = i*5 | ||
return i + 10 |
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.
See this test. The header file will be created and will be used in the original file.
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.
Ah, the generated file contains the header file?
I think we still need a handwritten file that includes it, to be sure that all the arguments are compatible.
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.
% lpython --show-c integration_tests/bindc_03.py > b.c
Will generate two file.
- main file:
#include <complex.h>
#include <inttypes.h>
#include "_test_bindc_03_my_header.h"
#include "bindc_03b.h"
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <lfortran_intrinsics.h>
struct dimension_descriptor
{
int32_t lower_bound, length;
};
struct ArrayWrapped {
void* array;
};
struct i32
{
int32_t *data;
struct dimension_descriptor dims[32];
int32_t n_dims;
bool is_allocated;
};
inline void struct_deepcopy_ArrayWrapped(struct ArrayWrapped* src, struct ArrayWrapped* dest);
// Implementations
int32_t __lpython_overloaded_4___lpython_floordiv(int32_t a, int32_t b)
{
int32_t _lpython_return_variable;
double r;
int32_t result;
r = (double)(a)/(double)(b);
result = (int32_t)(r);
if (r >= 0.00000000000000000e+00 || (double)(result) == r) {
_lpython_return_variable = result;
return _lpython_return_variable;
}
_lpython_return_variable = result - 1;
return _lpython_return_variable;
}
int32_t __lpython_overloaded_2___mod(int32_t a, int32_t b)
{
int32_t _lpython_return_variable;
_lpython_return_variable = a - __lpython_overloaded_4___lpython_floordiv(a, b)*b;
return _lpython_return_variable;
}
float _lfortran_caimag(float complex x);
double _lfortran_zaimag(double complex x);
void gpy(void* a, int32_t value, bool offset_value)
{
g(a, value, offset_value);
}
void f(void* q_void)
{
int32_t el;
int32_t i;
struct i32 q_value;
struct i32* q = &q_value;
q->n_dims = 1;
q->dims[0].lower_bound = 0;
q->dims[0].length = 0;
q->data = (int32_t*) q_void;
for (i=0; i<=10 - 1; i++) {
{
void* q2;
q2 = (void*) &q->data[(i - q->dims[0].lower_bound)];
gpy(q2, i*i, (bool)(__lpython_overloaded_2___mod(i, 2)));
el = q->data[(i - q->dims[0].lower_bound)];
printf("%d\n", el);
ASSERT(el == i*i + __lpython_overloaded_2___mod(i, 2));
}
}
}
void h(void* q_void)
{
int32_t el;
int32_t i;
struct i32 q_value;
struct i32* q = &q_value;
q->n_dims = 1;
q->dims[0].lower_bound = 0;
q->dims[0].length = 0;
q->data = (int32_t*) q_void;
for (i=0; i<=10 - 1; i++) {
{
el = q->data[(i - q->dims[0].lower_bound)];
printf("%d\n", el);
ASSERT(el == i*i + __lpython_overloaded_2___mod(i, 2));
}
}
}
void run()
{
void* a;
struct ArrayWrapped array_wrapped_value;
struct ArrayWrapped* array_wrapped = &array_wrapped_value;
struct ArrayWrapped array_wrapped1_value;
struct ArrayWrapped* array_wrapped1 = &array_wrapped1_value;
uint64_t q;
int32_t size;
void* x;
array_wrapped->array = a;
size = 10;
a = get_array(size);
ASSERT(a != NULL);
array_wrapped->array = a;
f(array_wrapped->array);
q = (uint64_t)(a);
x = (void*)(q);
array_wrapped->array = x;
f(array_wrapped->array);
struct_deepcopy_ArrayWrapped(array_wrapped, array_wrapped1);
h(array_wrapped1->array);
ASSERT(test_emit_header_ccallable() == 35);
}
void _lpython_main_program()
{
run();
}
int main(int argc, char* argv[])
{
_lpython_set_argv(argc, argv);
_lpython_main_program();
return 0;
}
void struct_deepcopy_ArrayWrapped(struct ArrayWrapped* src, struct ArrayWrapped* dest) {
dest->array = src->array;
}
- header file:
#ifndef _TEST_BINDC_03_MY_HEADER_H
#define _TEST_BINDC_03_MY_HEADER_H
#include <complex.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <lfortran_intrinsics.h>
int32_t test_emit_header_ccallable()
{
int32_t _lpython_return_variable;
int32_t i;
i = 5;
ASSERT(i == 5);
i = i*5;
_lpython_return_variable = i + 10;
return _lpython_return_variable;
}
#endif
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.
I think we still need a handwritten file that includes it, to be sure that all the arguments are compatible.
Yeah, you're right. ccallable
needs to be updated in the LLVM backend so that it can call from C.
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 test_emit_header_ccallable
must be in a C file, not a header file, otherwise the function will be generated twice by the C compiler and you will get linking errors.
Fixes #1797