Skip to content

Commit 2eb3978

Browse files
aykevldeadprogram
authored andcommitted
cgo: add support for printf
The C printf function is sometimes needed for C files included using CGo. This commit makes sure they're available on all systems where CGo is fully supported (that is, everywhere except on AVR). For baremetal systems using picolibc, I've picked the integer-only version of printf to save on flash size. We might want to consider providing a way to pick the floating point version instead, if needed.
1 parent 3021e16 commit 2eb3978

File tree

9 files changed

+45
-7
lines changed

9 files changed

+45
-7
lines changed

GNUmakefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,7 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
856856
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
857857
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
858858
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
859+
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/stdio
859860
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
860861
@mkdir -p build/release/tinygo/lib/musl/arch
861862
@mkdir -p build/release/tinygo/lib/musl/crt
@@ -891,10 +892,12 @@ endif
891892
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
892893
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
893894
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
895+
@cp -rp lib/musl/src/locale build/release/tinygo/lib/musl/src
894896
@cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src
895897
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
896898
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
897899
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
900+
@cp -rp lib/musl/src/multibyte build/release/tinygo/lib/musl/src
898901
@cp -rp lib/musl/src/signal build/release/tinygo/lib/musl/src
899902
@cp -rp lib/musl/src/stdio build/release/tinygo/lib/musl/src
900903
@cp -rp lib/musl/src/string build/release/tinygo/lib/musl/src
@@ -904,6 +907,7 @@ endif
904907
@cp -rp lib/mingw-w64/mingw-w64-crt/def-include build/release/tinygo/lib/mingw-w64/mingw-w64-crt
905908
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/api-ms-win-crt-* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
906909
@cp -rp lib/mingw-w64/mingw-w64-crt/lib-common/kernel32.def.in build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
910+
@cp -rp lib/mingw-w64/mingw-w64-crt/stdio/ucrt_* build/release/tinygo/lib/mingw-w64/mingw-w64-crt/stdio
907911
@cp -rp lib/mingw-w64/mingw-w64-headers/crt/ build/release/tinygo/lib/mingw-w64/mingw-w64-headers
908912
@cp -rp lib/mingw-w64/mingw-w64-headers/defaults/include build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
909913
@cp -rp lib/nrfx/* build/release/tinygo/lib/nrfx

builder/build.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
176176
defer unlock()
177177
libcDependencies = append(libcDependencies, libcJob)
178178
case "mingw-w64":
179-
_, unlock, err := libMinGW.load(config, tmpdir)
179+
job, unlock, err := libMinGW.load(config, tmpdir)
180180
if err != nil {
181181
return BuildResult{}, err
182182
}
183-
unlock()
183+
defer unlock()
184+
libcDependencies = append(libcDependencies, job)
184185
libcDependencies = append(libcDependencies, makeMinGWExtraLibs(tmpdir, config.GOARCH())...)
185186
case "":
186187
// no library specified, so nothing to do

builder/mingw-w64.go

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,30 @@ var libMinGW = Library{
2727
_, err = io.Copy(outf, inf)
2828
return err
2929
},
30-
sourceDir: func() string { return "" }, // unused
30+
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/mingw-w64") },
3131
cflags: func(target, headerPath string) []string {
32-
// No flags necessary because there are no files to compile.
33-
return nil
32+
mingwDir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/mingw-w64")
33+
return []string{
34+
"-nostdlibinc",
35+
"-isystem", mingwDir + "/mingw-w64-headers/crt",
36+
"-I", mingwDir + "/mingw-w64-headers/defaults/include",
37+
"-I" + headerPath,
38+
}
3439
},
3540
librarySources: func(target string) ([]string, error) {
36-
// We only use the UCRT DLL file. No source files necessary.
37-
return nil, nil
41+
// These files are needed so that printf and the like are supported.
42+
sources := []string{
43+
"mingw-w64-crt/stdio/ucrt_fprintf.c",
44+
"mingw-w64-crt/stdio/ucrt_fwprintf.c",
45+
"mingw-w64-crt/stdio/ucrt_printf.c",
46+
"mingw-w64-crt/stdio/ucrt_snprintf.c",
47+
"mingw-w64-crt/stdio/ucrt_sprintf.c",
48+
"mingw-w64-crt/stdio/ucrt_vfprintf.c",
49+
"mingw-w64-crt/stdio/ucrt_vprintf.c",
50+
"mingw-w64-crt/stdio/ucrt_vsnprintf.c",
51+
"mingw-w64-crt/stdio/ucrt_vsprintf.c",
52+
}
53+
return sources, nil
3854
},
3955
}
4056

builder/musl.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ var libMusl = Library{
9292
"-Wno-ignored-pragmas",
9393
"-Wno-tautological-constant-out-of-range-compare",
9494
"-Wno-deprecated-non-prototype",
95+
"-Wno-format",
96+
"-Wno-parentheses",
9597
"-Qunused-arguments",
9698
// Select include dirs. Don't include standard library includes
9799
// (that would introduce host dependencies and other complications),
@@ -119,11 +121,13 @@ var libMusl = Library{
119121
"internal/syscall_ret.c",
120122
"internal/vdso.c",
121123
"legacy/*.c",
124+
"locale/*.c",
122125
"linux/*.c",
123126
"malloc/*.c",
124127
"malloc/mallocng/*.c",
125128
"mman/*.c",
126129
"math/*.c",
130+
"multibyte/*.c",
127131
"signal/*.c",
128132
"stdio/*.c",
129133
"string/*.c",

builder/picolibc.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ var libPicolibc = Library{
2929
"-D_HAVE_ALIAS_ATTRIBUTE",
3030
"-DTINY_STDIO",
3131
"-DPOSIX_IO",
32+
"-DFORMAT_DEFAULT_INTEGER", // use __i_vfprintf and __i_vfscanf by default
3233
"-D_IEEE_LIBM",
3334
"-D__OBSOLETE_MATH_FLOAT=1", // use old math code that doesn't expect a FPU
3435
"-D__OBSOLETE_MATH_DOUBLE=0",

testdata/cgo/main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <math.h>
22
#include "main.h"
3+
#include <stdio.h>
34

45
int global = 3;
56
bool globalBool = 1;
@@ -72,3 +73,7 @@ void arraydecay(int buf1[5], int buf2[3][8], int buf3[4][7][2]) {
7273
double doSqrt(double x) {
7374
return sqrt(x);
7475
}
76+
77+
void printf_single_int(char *format, int arg) {
78+
printf(format, arg);
79+
}

testdata/cgo/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ func main() {
179179
// libc: test basic stdio functionality
180180
putsBuf := []byte("line written using C puts\x00")
181181
C.puts((*C.char)(unsafe.Pointer(&putsBuf[0])))
182+
183+
// libc: test whether printf works in C.
184+
printfBuf := []byte("line written using C printf with value=%d\n\x00")
185+
C.printf_single_int((*C.char)(unsafe.Pointer(&printfBuf[0])), -21)
182186
}
183187

184188
func printUnion(union C.joined_t) C.joined_t {

testdata/cgo/main.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,5 @@ typedef int arraydecay_buf3[4][7][2];
152152
void arraydecay(int buf1[5], int buf2[3][8], arraydecay_buf3 buf3);
153153

154154
double doSqrt(double);
155+
156+
void printf_single_int(char *format, int arg);

testdata/cgo/out.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,4 @@ copied string: foobar
7777
CGo sqrt(3): +1.732051e+000
7878
C sqrt(3): +1.732051e+000
7979
line written using C puts
80+
line written using C printf with value=-21

0 commit comments

Comments
 (0)