thank you for your replies. your help and insights are much appreciated.
I'm loving TCC!
however, i've reached the limit of my current hot-swap function hack that uses two state-commingling TCC instances. after a while, the instances stop working properly and I get strange compile errors.
so, i am interested in executing some hack to allow multiple independent TCC instances in the same application. i am certain that "the old trick of just opening a pipe, forking and
then sending back the result" will not work for my purposes. if i can't get one of these hacks working, i have to go look at LLVM and cling again :/
as i understand it, option 2 (from Giovanni Mascellani) is using libtcc to compile libtcc from source into memory. that sounds awesome. i spent most of today trying this on windows.. and also learning to compile TCC on windows. here's my attempt:
// boot.cpp
//
// tcc version 0.9.27 (x86_64 Windows)
// install: c:/tcc
// include:
// c:/tcc/include
// c:/tcc/include/winapi
// libraries:
// c:/tcc/lib
// C:/Windows/system32
// libtcc1:
// c:/tcc/lib/libtcc1-64.a
//
// build and run with:
// cd tinycc
// cl /MD boot.cpp c:\tcc\libtcc64.lib
// boot.exe
//
// fails like this:
// need 457827 bytes
// relocating to 21f0a402fd0
// tcc: error: library 'libtcc1-64.a' not found
// Assertion failed: dec != nullptr, file boot.cpp, line 69
//
#include "libtcc.h"
#include <cassert>
#include <iostream>
int main() {
TCCState* instance = tcc_new();
// i'm on Windows 10 x64. what else do i need here?
tcc_set_options(instance, "-shared");
tcc_define_symbol(instance, "TCC_TARGET_X86_64", "");
tcc_define_symbol(instance, "TCC_TARGET_PE", "");
tcc_define_symbol(instance, "LIBTCC_AS_DLL", "");
// i needed this define on Windows to get tcc_relocate in the DLL
tcc_define_symbol(instance, "TCC_IS_NATIVE", "");
tcc_set_output_type(instance, TCC_OUTPUT_MEMORY);
// maybe add more source files?
tcc_add_file(instance, "libtcc.c");
int size = tcc_relocate(instance, (void*)0);
void* memory = malloc(size);
printf("need %d bytes\n", size);
printf("relocating to %llx\n", (unsigned long long int)memory);
tcc_relocate(instance, memory);
// TCCState *tcc_new(void);
using New = TCCState* (*)(void);
New _new = (New)tcc_get_symbol(instance, "tcc_new");
assert(_new != nullptr);
// int tcc_set_output_type(TCCState *s, int output_type);
using SetOutputType = int (*)(TCCState*, int);
SetOutputType _set_output_type =
(SetOutputType)tcc_get_symbol(instance, "tcc_set_output_type");
assert(_set_output_type != nullptr);
// int tcc_compile_string(TCCState *s, const char *buf);
using CompileString = int (*)(TCCState*, const char*);
CompileString _compile_string =
(CompileString)tcc_get_symbol(instance, "tcc_compile_string");
assert(_compile_string != nullptr);
// int tcc_relocate(TCCState *s1, void *ptr);
using Relocate = int (*)(TCCState*, void*);
Relocate _relocate = (Relocate)tcc_get_symbol(instance, "tcc_relocate");
assert(_relocate != nullptr);
// void *tcc_get_symbol(TCCState *s, const char *name);
using GetSymbol = void* (*)(TCCState*, const char*);
GetSymbol _get_symbol = (GetSymbol)tcc_get_symbol(instance, "tcc_get_symbol");
assert(_get_symbol != nullptr);
// can i delete the instance now??
// my experiments suggest no.
// tcc_delete(instance);
// use the new, relocated instance to compile something
TCCState* born_in_memory = _new();
assert(born_in_memory != nullptr);
_set_output_type(born_in_memory, TCC_OUTPUT_MEMORY);
_compile_string(born_in_memory, "int dec(int t) { return t - 1; }");
_relocate(born_in_memory, TCC_RELOCATE_AUTO);
using Foo = int (*)(int);
Foo dec = (Foo)_get_symbol(born_in_memory, "dec");
assert(dec != nullptr);
printf("dec(2) == %d\b", dec(2));
}
am i on the right track here? any suggestions would help a lot. i think i could add the path to libtcc1-64.a, but i would rather compile all the .c files i need so there's no need to find libtcc1-64.a at runtime.
-
option 1 (from Christian Jullien) is something that i don't quite understand. i am just failing to connect the dots given i the pseudocode:
// tcc1.cpp:
namespace tcc1 {
#include "libtcc.h"
// does this mean i should compile libtcc as c++ (not c) under the tcc1 namespace?
};
// tcc2.cpp:
namespace tcc2 {
#include "libtcc.h"
// does this mean i should compile libtcc as c++ (not c) AGAIN under the tcc2 namespace?
// OR does this mean i should write a wrapper interface for libtcc here?
};
// main.cpp:
int main() {
tcc1::TCCState* a = nullptr;
char (*A)(int) = nullptr;
assert((a = tcc1::tcc_new()) != nullptr);
tcc2::TCCState* b =
tcc2::tcc_new(); // remove this line to make the program work
}
also "But it may not be so simple. For some projects it worked flawlessly and failed for some others" is mysterious to me. my apologies for being too ignorant to put it together! a little more help on this option might help me a lot.
sorry for the long email.
-- karl