Skip to content

Commit 1d14941

Browse files
committed
Add base for supporting strings s and void in C loader.
1 parent 1001fcd commit 1d14941

File tree

7 files changed

+292
-7
lines changed

7 files changed

+292
-7
lines changed

source/configuration/source/configuration_object.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ configuration configuration_object_initialize(const char *name, const char *path
104104

105105
if (config->source == NULL)
106106
{
107-
log_write("metacall", LOG_LEVEL_ERROR, "Failed to load configuration %s from %s", name, path);
108-
109107
free(config);
110108

111109
return NULL;
@@ -268,6 +266,8 @@ int configuration_object_childs(configuration config, vector childs, set storage
268266

269267
if (child == NULL)
270268
{
269+
log_write("metacall", LOG_LEVEL_ERROR, "Failed to load configuration %s from %s", (char *)key, path);
270+
271271
return 1;
272272
}
273273

source/loaders/c_loader/source/c_loader_impl.cpp

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -633,10 +633,14 @@ ffi_type *c_loader_impl_ffi_type(type_id id)
633633
return &ffi_type_float;
634634
case TYPE_DOUBLE:
635635
return &ffi_type_double;
636+
case TYPE_STRING:
637+
return &ffi_type_pointer;
636638
case TYPE_PTR:
637639
return &ffi_type_pointer;
638640
case TYPE_FUNCTION:
639641
return &ffi_type_pointer;
642+
case TYPE_NULL:
643+
return &ffi_type_void;
640644
}
641645

642646
return &ffi_type_void;
@@ -683,6 +687,11 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
683687

684688
closures.push_back(closure);
685689
}
690+
else if (id == TYPE_STRING)
691+
{
692+
char *str = value_to_string((value)args[args_count]);
693+
c_function->values[args_count] = &str;
694+
}
686695
else
687696
{
688697
c_function->values[args_count] = value_data((value)args[args_count]);
@@ -693,9 +702,7 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
693702
size_t ret_size = value_type_id_size(ret_id);
694703
void *ret = NULL;
695704

696-
/* TODO: This if is not correct because the sizes of strings, objects, etc are
697-
relative to the pointer, not the value contents, we should review this */
698-
if (ret_size <= sizeof(ffi_arg))
705+
if (ret_size <= sizeof(ffi_arg) && ret_id < TYPE_STRING)
699706
{
700707
ffi_arg result;
701708

@@ -705,9 +712,26 @@ function_return function_c_interface_invoke(function func, function_impl impl, f
705712
}
706713
else
707714
{
708-
ret = value_type_create(NULL, ret_size, ret_id);
715+
void *result = NULL;
716+
void *result_ptr = &result;
709717

710-
ffi_call(&c_function->cif, FFI_FN(c_function->address), value_data(ret), c_function->values);
718+
if (ret_id == TYPE_NULL)
719+
{
720+
result = value_create_null();
721+
result_ptr = NULL;
722+
}
723+
else if (ret_id != TYPE_STRING)
724+
{
725+
result = ret = value_type_create(NULL, ret_size, ret_id);
726+
}
727+
728+
ffi_call(&c_function->cif, FFI_FN(c_function->address), result_ptr, c_function->values);
729+
730+
if (ret_id == TYPE_STRING)
731+
{
732+
char *str = (char *)result;
733+
ret = value_create_string(str, strlen(str));
734+
}
711735
}
712736

713737
/* Clear allocated closures if any */
@@ -838,6 +862,11 @@ int c_loader_impl_initialize_types(loader_impl impl)
838862
{ TYPE_FLOAT, "float" },
839863
{ TYPE_DOUBLE, "double" },
840864

865+
{ TYPE_STRING, "unsigned char *" },
866+
{ TYPE_STRING, "char *" },
867+
{ TYPE_STRING, "const unsigned char *" },
868+
{ TYPE_STRING, "const char *" },
869+
841870
{ TYPE_NULL, "void" }
842871

843872
/* TODO: Do more types */

source/scripts/c/compiled/source/compiled.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
#include <assert.h>
12
#include <stdio.h>
3+
#include <string.h>
24

35
void compiled_print(int a, double b)
46
{
@@ -9,3 +11,15 @@ long compiled_sum(long a, long b)
911
{
1012
return a + b;
1113
}
14+
15+
char *return_text(void)
16+
{
17+
static char input[] = "hello";
18+
return input;
19+
}
20+
21+
void process_text(char *input)
22+
{
23+
printf("'%s'\n", input);
24+
assert(strcmp(input, "test_test") == 0);
25+
}

source/tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ add_subdirectory(metacall_node_port_test)
129129
add_subdirectory(metacall_node_port_await_test)
130130
add_subdirectory(metacall_node_port_rs_test)
131131
add_subdirectory(metacall_node_port_c_lib_test)
132+
add_subdirectory(metacall_node_port_c_test)
132133
add_subdirectory(metacall_node_python_port_mock_test)
133134
add_subdirectory(metacall_node_python_port_ruby_test)
134135
add_subdirectory(metacall_node_python_ruby_test)
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Check if this loader is enabled
2+
if(NOT OPTION_BUILD_LOADERS OR NOT OPTION_BUILD_LOADERS_NODE OR NOT OPTION_BUILD_LOADERS_C OR NOT OPTION_BUILD_PORTS OR NOT OPTION_BUILD_PORTS_NODE)
3+
return()
4+
endif()
5+
6+
#
7+
# Executable name and options
8+
#
9+
10+
# Target name
11+
set(target metacall-node-port-c-test)
12+
message(STATUS "Test ${target}")
13+
14+
#
15+
# Compiler warnings
16+
#
17+
18+
include(Warnings)
19+
20+
#
21+
# Compiler security
22+
#
23+
24+
include(SecurityFlags)
25+
26+
#
27+
# Sources
28+
#
29+
30+
set(include_path "${CMAKE_CURRENT_SOURCE_DIR}/include/${target}")
31+
set(source_path "${CMAKE_CURRENT_SOURCE_DIR}/source")
32+
33+
set(sources
34+
${source_path}/main.cpp
35+
${source_path}/metacall_node_port_c_test.cpp
36+
)
37+
38+
# Group source files
39+
set(header_group "Header Files (API)")
40+
set(source_group "Source Files")
41+
source_group_by_path(${include_path} "\\\\.h$|\\\\.hpp$"
42+
${header_group} ${headers})
43+
source_group_by_path(${source_path} "\\\\.cpp$|\\\\.c$|\\\\.h$|\\\\.hpp$"
44+
${source_group} ${sources})
45+
46+
#
47+
# Create executable
48+
#
49+
50+
# Build executable
51+
add_executable(${target}
52+
${sources}
53+
)
54+
55+
# Create namespaced alias
56+
add_executable(${META_PROJECT_NAME}::${target} ALIAS ${target})
57+
58+
#
59+
# Project options
60+
#
61+
62+
set_target_properties(${target}
63+
PROPERTIES
64+
${DEFAULT_PROJECT_OPTIONS}
65+
FOLDER "${IDE_FOLDER}"
66+
)
67+
68+
#
69+
# Include directories
70+
#
71+
72+
target_include_directories(${target}
73+
PRIVATE
74+
${DEFAULT_INCLUDE_DIRECTORIES}
75+
${PROJECT_BINARY_DIR}/source/include
76+
)
77+
78+
#
79+
# Libraries
80+
#
81+
82+
target_link_libraries(${target}
83+
PRIVATE
84+
${DEFAULT_LIBRARIES}
85+
86+
GTest
87+
88+
${META_PROJECT_NAME}::metacall
89+
)
90+
91+
#
92+
# Compile definitions
93+
#
94+
95+
target_compile_definitions(${target}
96+
PRIVATE
97+
${DEFAULT_COMPILE_DEFINITIONS}
98+
99+
# NodeJS Port path
100+
METACALL_NODE_PORT_PATH="${CMAKE_SOURCE_DIR}/source/ports/node_port/index.js"
101+
)
102+
103+
#
104+
# Compile options
105+
#
106+
107+
target_compile_options(${target}
108+
PRIVATE
109+
${DEFAULT_COMPILE_OPTIONS}
110+
)
111+
112+
#
113+
# Compile features
114+
#
115+
116+
target_compile_features(${target}
117+
PRIVATE
118+
cxx_std_17
119+
)
120+
121+
#
122+
# Linker options
123+
#
124+
125+
target_link_options(${target}
126+
PRIVATE
127+
${DEFAULT_LINKER_OPTIONS}
128+
)
129+
130+
#
131+
# Define test
132+
#
133+
134+
add_test(NAME ${target}
135+
COMMAND $<TARGET_FILE:${target}>
136+
)
137+
138+
#
139+
# Define dependencies
140+
#
141+
142+
add_dependencies(${target}
143+
node_port
144+
node_loader
145+
c_loader
146+
)
147+
148+
#
149+
# Define test properties
150+
#
151+
152+
set_property(TEST ${target}
153+
PROPERTY LABELS ${target}
154+
)
155+
156+
include(TestEnvironmentVariables)
157+
158+
test_environment_variables(${target}
159+
""
160+
${TESTS_ENVIRONMENT_VARIABLES}
161+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* MetaCall Library by Parra Studios
3+
* A library for providing a foreign function interface calls.
4+
*
5+
* Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia <vic798@gmail.com>
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
21+
#include <gtest/gtest.h>
22+
23+
int main(int argc, char *argv[])
24+
{
25+
::testing::InitGoogleTest(&argc, argv);
26+
27+
return RUN_ALL_TESTS();
28+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* MetaCall Library by Parra Studios
3+
* A library for providing a foreign function interface calls.
4+
*
5+
* Copyright (C) 2016 - 2025 Vicente Eduardo Ferrer Garcia <vic798@gmail.com>
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*
19+
*/
20+
21+
#include <gtest/gtest.h>
22+
23+
#include <metacall/metacall.h>
24+
#include <metacall/metacall_loaders.h>
25+
#include <metacall/metacall_value.h>
26+
27+
class metacall_node_port_c_test : public testing::Test
28+
{
29+
public:
30+
};
31+
32+
TEST_F(metacall_node_port_c_test, DefaultConstructor)
33+
{
34+
metacall_print_info();
35+
36+
ASSERT_EQ((int)0, (int)metacall_initialize());
37+
38+
static const char buffer[] =
39+
"const assert = require('assert');\n"
40+
"const { metacall_load_from_file_export } = require('" METACALL_NODE_PORT_PATH "');\n"
41+
"const { return_text, process_text } = metacall_load_from_file_export('c', ['compiled.c']);\n"
42+
"const result = return_text();\n"
43+
"console.log(`'${result}'`);\n"
44+
"assert(result == 'hello');\n"
45+
"console.log(result);\n"
46+
"process_text('test_test');\n"
47+
"\n";
48+
49+
ASSERT_EQ((int)0, (int)metacall_load_from_memory("node", buffer, sizeof(buffer), NULL));
50+
51+
metacall_destroy();
52+
}

0 commit comments

Comments
 (0)