Issue
I'm trying to create a simple hello world program that uses libtcc to dynamically compile the code. It works fine when I compile it natively on linux. However, there are link errors when I try to cross-compile it from linux to windows with mingw-w64.
Here are the commands I use to compile for linux:
$ cmake -S . -B build && cmake --build build
-- The C compiler identification is GNU 12.2.0
-- The CXX compiler identification is GNU 12.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /workdir/project/build
[ 10%] Creating directories for 'tcc_proj'
[ 20%] No download step for 'tcc_proj'
[ 30%] No update step for 'tcc_proj'
[ 40%] No patch step for 'tcc_proj'
[ 50%] Performing configure step for 'tcc_proj'
Binary directory /usr/local/bin
TinyCC directory /usr/local/lib/tcc
Library directory /usr/local/lib
Include directory /usr/local/include
Manual directory /usr/local/share/man
Info directory /usr/local/share/info
Doc directory /usr/local/share/doc
Source path /workdir/project/tinycc
C compiler gcc (12.2)
Target OS Linux
CPU x86_64
Triplet x86_64-linux-gnu
Creating config.mak and config.h
[ 60%] Performing build step for 'tcc_proj'
[ 70%] No install step for 'tcc_proj'
[ 80%] Completed 'tcc_proj'
[ 80%] Built target tcc_proj
[ 90%] Building C object CMakeFiles/hello.dir/hello.c.o
[100%] Linking C executable hello
[100%] Built target hello
And here are the commands I use to compile for windows:
$ cmake -S . -B build-win -DCMAKE_TOOLCHAIN_FILE=win-x64-static.cmake && cmake --build build-win
-- Configuring done
-- Generating done
-- Build files have been written to: /workdir/project/build-win
[ 10%] Performing configure step for 'tcc_proj'
Binary directory C:/Program Files/tcc
TinyCC directory C:/Program Files/tcc
Library directory C:/Program Files/tcc/libtcc
Doc directory C:/Program Files/tcc/doc
Source path /workdir/project/tinycc
C compiler gcc (0.0)
Target OS WIN32
CPU x86_64
Config static WIN32
Creating config.mak and config.h
config.h is unchanged
[ 20%] Performing build step for 'tcc_proj'
[ 30%] No install step for 'tcc_proj'
[ 40%] Completed 'tcc_proj'
[ 80%] Built target tcc_proj
[ 90%] Linking C executable hello.exe
/usr/bin/x86_64-w64-mingw32-ld: CMakeFiles/hello.dir/objects.a(hello.c.obj):hello.c:(.text.startup+0xd): undefined reference to `tcc_new'
/usr/bin/x86_64-w64-mingw32-ld: CMakeFiles/hello.dir/objects.a(hello.c.obj):hello.c:(.text.startup+0x1d): undefined reference to `tcc_set_output_type'
/usr/bin/x86_64-w64-mingw32-ld: CMakeFiles/hello.dir/objects.a(hello.c.obj):hello.c:(.text.startup+0x2c): undefined reference to `tcc_compile_string'
/usr/bin/x86_64-w64-mingw32-ld: CMakeFiles/hello.dir/objects.a(hello.c.obj):hello.c:(.text.startup+0x36): undefined reference to `tcc_relocate'
/usr/bin/x86_64-w64-mingw32-ld: CMakeFiles/hello.dir/objects.a(hello.c.obj):hello.c:(.text.startup+0x4c): undefined reference to `tcc_relocate'
/usr/bin/x86_64-w64-mingw32-ld: CMakeFiles/hello.dir/objects.a(hello.c.obj):hello.c:(.text.startup+0x5b): undefined reference to `tcc_get_symbol'
/usr/bin/x86_64-w64-mingw32-ld: CMakeFiles/hello.dir/objects.a(hello.c.obj):hello.c:(.text.startup+0x66): undefined reference to `tcc_delete'
collect2: error: ld returned 1 exit status
gmake[2]: *** [CMakeFiles/hello.dir/build.make:101: hello.exe] Error 1
gmake[1]: *** [CMakeFiles/Makefile2:111: CMakeFiles/hello.dir/all] Error 2
gmake: *** [Makefile:91: all] Error 2
In both cases, the build process creates a build-win/tcc_proj-prefix/src/tcc_proj-build/libtcc.a file.
The directory structure of the project is as follows: on the root there is the tinycc repository, a hello.c file, a CMakeLists.txt file, and a win-x64-static.cmake file.
The url of the tinycc reposistory is: https://repo.or.cz/tinycc.git
The content of hello.c is:
#include <stdlib.h>
#include <stdio.h>
#include "libtcc.h"
char hello_code[] =
"#include <stdio.h>\n"
"\n"
"int main() {\n"
" printf(\"Hello World\\n\");\n"
" return 0;\n"
"};\n";
int main(int argc, char **argv)
{
TCCState *s;
int (*main_func)(int, char**);
void *mem;
s = tcc_new();
tcc_set_output_type(s, TCC_OUTPUT_MEMORY);
tcc_compile_string(s, hello_code);
mem = malloc(tcc_relocate(s, NULL));
tcc_relocate(s, mem);
main_func = tcc_get_symbol(s, "main");
tcc_delete(s);
printf("main_func returned: %d\n", main_func(0, NULL));
free(mem);
return 0;
}
The content of CMakeFiles.txt is:
CMAKE_MINIMUM_REQUIRED(VERSION 3.0)
PROJECT(tcc)
include(ExternalProject)
if (WIN32)
ExternalProject_Add(tcc_proj SOURCE_DIR ${CMAKE_SOURCE_DIR}/tinycc CONFIGURE_COMMAND "${CMAKE_SOURCE_DIR}/tinycc/configure" --enable-static --config-mingw32 BUILD_COMMAND make INSTALL_COMMAND "")
else ()
ExternalProject_Add(tcc_proj SOURCE_DIR ${CMAKE_SOURCE_DIR}/tinycc CONFIGURE_COMMAND "${CMAKE_SOURCE_DIR}/tinycc/configure" BUILD_COMMAND make INSTALL_COMMAND "")
endif (WIN32)
ExternalProject_Get_Property(tcc_proj source_dir)
list(APPEND LIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tinycc/")
list(APPEND LIB_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/tinycc/include/")
add_library(tcc STATIC IMPORTED)
set(LIB_LOCATION tcc_proj-prefix/src/tcc_proj-build/libtcc.a)
set_target_properties(tcc PROPERTIES IMPORTED_LOCATION ${LIB_LOCATION} INTERFACE_INCLUDE_DIRECTORIES "${LIB_INCLUDE_DIRS}")
add_executable(hello "./hello.c")
target_link_libraries(hello PRIVATE tcc)
And the content of win-x64-static.cmake is:
# Toolchain to build from Linux to Windows
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
# cross compilers to use for C, C++ and Fortran
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
# target environment on the build host system
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -static -Os")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -Os")
Solution
I was able to solve the problem. In order to cross-compile libtcc, it's required to specify the flag --cross-prefix
, in addition to the --config-mingw32
. So, the windows cmake configuration should be:
ExternalProject_Add(tcc_proj SOURCE_DIR ${CMAKE_SOURCE_DIR}/tinycc CONFIGURE_COMMAND "${CMAKE_SOURCE_DIR}/tinycc/configure" --enable-static --config-mingw32 --cross-prefix=${TOOLCHAIN_PREFIX}- BUILD_COMMAND make INSTALL_COMMAND "")
Answered By - André Rosa Answer Checked By - Timothy Miller (WPSolving Admin)