Repository: Konstantin8105/c4go
Pull request #301 (2019-03-04 10:38:12)

auto-binding for function without implementation

codecov[bot]: # [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/301?src=pr&el=h1) Report
> Merging [#301](https://codecov.io/gh/Konstantin8105/c4go/pull/301?src=pr&el=desc) into [master](https://codecov.io/gh/Konstantin8105/c4go/commit/f79c4b1904e7e6739e2f1f075d78d9021a6faf01?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `86.75%`.

[![Impacted file tree graph](https://codecov.io/gh/Konstantin8105/c4go/pull/301/graphs/tree.svg?width=650&token=esH2rHXlZ2&height=150&src=pr)](https://codecov.io/gh/Konstantin8105/c4go/pull/301?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #301      +/-   ##
==========================================
- Coverage   86.79%   86.79%   -0.01%     
==========================================
  Files         184      185       +1     
  Lines       10071    10282     +211     
==========================================
+ Hits         8741     8924     +183     
- Misses        922      941      +19     
- Partials      408      417       +9
```


| [Impacted Files](https://codecov.io/gh/Konstantin8105/c4go/pull/301?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [main.go](https://codecov.io/gh/Konstantin8105/c4go/pull/301/diff?src=pr&el=tree#diff-bWFpbi5nbw==) | `100% <ø> (ø)` | :arrow_up: |
| [program/definition\_function.go](https://codecov.io/gh/Konstantin8105/c4go/pull/301/diff?src=pr&el=tree#diff-cHJvZ3JhbS9kZWZpbml0aW9uX2Z1bmN0aW9uLmdv) | `88.77% <100%> (+2.02%)` | :arrow_up: |
| [transpiler/call.go](https://codecov.io/gh/Konstantin8105/c4go/pull/301/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9jYWxsLmdv) | `78.47% <100%> (+0.11%)` | :arrow_up: |
| [preprocessor/preprocessor.go](https://codecov.io/gh/Konstantin8105/c4go/pull/301/diff?src=pr&el=tree#diff-cHJlcHJvY2Vzc29yL3ByZXByb2Nlc3Nvci5nbw==) | `83.27% <83.67%> (-0.25%)` | :arrow_down: |
| [transpiler/bind.go](https://codecov.io/gh/Konstantin8105/c4go/pull/301/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci9iaW5kLmdv) | `84.25% <84.25%> (ø)` | |
| [transpiler/transpiler.go](https://codecov.io/gh/Konstantin8105/c4go/pull/301/diff?src=pr&el=tree#diff-dHJhbnNwaWxlci90cmFuc3BpbGVyLmdv) | `89.44% <96.15%> (+0.72%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/301?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Konstantin8105/c4go/pull/301?src=pr&el=footer). Last update [f79c4b1...e2bda5d](https://codecov.io/gh/Konstantin8105/c4go/pull/301?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/README.md b/README.md
index f7af01e..ce00114 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,66 @@ func main() {
 }
 ```
 
+# Example with binding function
+
+Run:
+
+```
+c4go transpile 
+```
+
+
+```c
+#include <stdio.h>
+#include <math.h>
+
+int main()
+{
+	int n;
+	double param = 8.0, result;
+	result = frexp(param,&n);
+	printf("result = %5.2f\n", result);
+	printf("n      = %d\n"   , n     );
+	return 0;
+}
+```
+
+`c4go` add automatically C binding for function without implementation:
+```golang
+//
+//	Package - transpiled by c4go
+//
+//	If you have found any issues, please raise an issue at:
+//	https://github.com/Konstantin8105/c4go/
+//
+
+package main
+
+// #include </usr/include/x86_64-linux-gnu/bits/mathcalls.h>
+import "C"
+
+import "github.com/Konstantin8105/c4go/noarch"
+import "unsafe"
+
+// main - transpiled function from  $GOPATH/src/github.com/Konstantin8105/c4go/examples/math.c:4
+func main() {
+	var n int
+	var param float64 = 8
+	var result float64
+	result = frexp(param, (*[100000000]int)(unsafe.Pointer(&n))[:])
+	noarch.Printf([]byte("result = %5.2f\n\x00"), result)
+	noarch.Printf([]byte("n      = %d\n\x00"), n)
+	return
+}
+
+func frexp(arg0 float64, arg1 []int) float64 {
+	return float64(C.frexp(C.double(arg0), (*_Ctype_int)(unsafe.Pointer(&arg1[0]))))
+}
+```
+
+
+
+
 # C standard library implementation
 
 ```
@@ -126,7 +186,7 @@ func main() {
             iso646.h	          	    undefined
             limits.h	          	    undefined
             locale.h	       3/3	         100%
-              math.h	     37/58	        63.8%
+              math.h	     38/58	        65.5%
             setjmp.h	       0/3	           0%
             signal.h	       3/3	         100%
             stdarg.h	       4/4	         100%
diff --git a/examples/math.c b/examples/math.c
new file mode 100644
index 0000000..f7b1eb2
--- /dev/null
+++ b/examples/math.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <math.h>
+
+int main() 
+{
+	int n;
+	double param = 8.0, result;
+	result = frexp(param,&n);
+	printf("result = %5.2f\n", result);
+	printf("n      = %d\n"   , n     );
+	return 0;
+}
diff --git a/main.go b/main.go
index 87b7830..3e0e5a8 100644
--- a/main.go
+++ b/main.go
@@ -355,7 +355,8 @@ func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP
 		fmt.Fprintln(os.Stdout, "Transpiling tree...")
 	}
 
-	err = transpiler.TranspileAST(args.outputFile, args.packageName, args.outsideStructs,
+	var source string
+	source, err = transpiler.TranspileAST(args.outputFile, args.packageName, args.outsideStructs,
 		p, tree[0].(ast.Node))
 	if err != nil {
 		for i := range astErrors {
@@ -369,7 +370,7 @@ func generateGoCode(args ProgramArgs, lines []string, filePP preprocessor.FilePP
 	if args.verbose {
 		fmt.Fprintln(os.Stdout, "Writing the output Go code...")
 	}
-	err = ioutil.WriteFile(outputFilePath, []byte(p.String()), 0644)
+	err = ioutil.WriteFile(outputFilePath, []byte(source), 0644)
 	if err != nil {
 		return fmt.Errorf("writing Go output file failed: %v", err)
 	}
diff --git a/preprocessor/preprocessor.go b/preprocessor/preprocessor.go
index 5d9ba7d..b15116e 100644
--- a/preprocessor/preprocessor.go
+++ b/preprocessor/preprocessor.go
@@ -102,8 +102,9 @@ type Comment struct {
 
 // IncludeHeader - struct for C include header
 type IncludeHeader struct {
-	HeaderName   string
-	IsUserSource bool
+	HeaderName     string
+	BaseHeaderName string
+	IsUserSource   bool
 }
 
 // FilePP a struct with all information about preprocessor C code
@@ -143,6 +144,7 @@ func NewFilePP(inputFiles, clangFlags []string, cppCode bool) (
 	if err != nil {
 		return
 	}
+
 	// Generate C header list
 	f.includes = generateIncludeList(us, all)
 
@@ -200,6 +202,74 @@ func NewFilePP(inputFiles, clangFlags []string, cppCode bool) (
 	}
 	f.pp = ([]byte)(strings.Join(lines, "\n"))
 
+	{
+		for i := range f.includes {
+			f.includes[i].BaseHeaderName = f.includes[i].HeaderName
+		}
+		// correct include names only for external Includes
+		var ier []string
+		ier, err = GetIeraphyIncludeList(inputFiles, clangFlags, cppCode)
+
+		// cut lines without pattern ". "
+	again:
+		for i := range ier {
+			remove := false
+			if len(ier[i]) == 0 {
+				remove = true
+			} else if ier[i][0] != '.' {
+				remove = true
+			} else if index := strings.Index(ier[i], ". "); index < 0 {
+				remove = true
+			}
+			if remove {
+				ier = append(ier[:i], ier[i+1:]...)
+				goto again
+			}
+		}
+
+		separator := func(line string) (level int, name string) {
+			for i := range line {
+				if line[i] == ' ' {
+					level = i
+					break
+				}
+			}
+			name = line[level+1:]
+			return
+		}
+
+		for i := range f.includes {
+			if f.includes[i].IsUserSource {
+				continue
+			}
+			// find position in Include ierarphy
+			var pos int = -1
+			for j := range ier {
+				if strings.Contains(ier[j], f.includes[i].BaseHeaderName) {
+					pos = j
+					break
+				}
+			}
+			if pos < 0 {
+				continue
+			}
+
+			// find level of line
+			level, _ := separator(ier[pos])
+
+			for j := pos; j > 0; j-- {
+				levelJ, nameJ := separator(ier[j])
+				if levelJ >= level {
+					continue
+				}
+				if f.IsUserSource(nameJ) {
+					break
+				}
+				f.includes[i].BaseHeaderName = nameJ
+				level = levelJ
+			}
+		}
+	}
 	return
 }
 
@@ -229,6 +299,16 @@ func (f FilePP) IsUserSource(in string) bool {
 	return false
 }
 
+// GetBaseInclude return base include
+func (f FilePP) GetBaseInclude(in string) string {
+	for i := range f.includes {
+		if in == f.includes[i].HeaderName {
+			return f.includes[i].BaseHeaderName
+		}
+	}
+	return in
+}
+
 // GetSnippet return short part of code inside preprocessor C code
 func (f FilePP) GetSnippet(file string,
 	line, lineEnd int,
@@ -457,7 +537,12 @@ func generateIncludeList(userList, allList []string) (
 // exit.o: exit.c tests.h
 func GetIncludeListWithUserSource(inputFiles, clangFlags []string, cppCode bool) (
 	lines []string, err error) {
-	return getIncludeList(inputFiles, clangFlags, "-MM", cppCode)
+	var out string
+	out, err = getIncludeList(inputFiles, clangFlags, []string{"-MM"}, cppCode)
+	if err != nil {
+		return
+	}
+	return parseIncludeList(out)
 }
 
 // GetIncludeFullList - Get full list of include files
@@ -471,11 +556,42 @@ func GetIncludeListWithUserSource(inputFiles, clangFlags []string, cppCode bool)
 //   / ........ and other
 func GetIncludeFullList(inputFiles, clangFlags []string, cppCode bool) (
 	lines []string, err error) {
-	return getIncludeList(inputFiles, clangFlags, "-M", cppCode)
+	var out string
+	out, err = getIncludeList(inputFiles, clangFlags, []string{"-M"}, cppCode)
+	if err != nil {
+		return
+	}
+	return parseIncludeList(out)
 }
 
-func getIncludeList(inputFiles, clangFlags []string, flag string, cppCode bool) (
+// GetIeraphyIncludeList - Get list of include files in ierarphy
+// Example:
+// clang -MM -H ./tests/math.c
+// . ./tests/tests.h
+// .. /usr/include/string.h
+// ... /usr/include/features.h
+// .... /usr/include/stdc-predef.h
+// .... /usr/include/x86_64-linux-gnu/sys/cdefs.h
+// ..... /usr/include/x86_64-linux-gnu/bits/wordsize.h
+// .... /usr/include/x86_64-linux-gnu/gnu/stubs.h
+// ..... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h
+// ... /usr/lib/llvm-6.0/lib/clang/6.0.0/include/stddef.h
+// ... /usr/include/xlocale.h
+// .. /usr/include/math.h
+// ... /usr/include/x86_64-linux-gnu/bits/math-vector.h
+func GetIeraphyIncludeList(inputFiles, clangFlags []string, cppCode bool) (
 	lines []string, err error) {
+	var out string
+	out, err = getIncludeList(inputFiles, clangFlags, []string{"-MM", "-H"}, cppCode)
+	if err != nil {
+		return
+	}
+	return strings.Split(out, "\n"), nil
+}
+
+// getIncludeList return stdout lines
+func getIncludeList(inputFiles, clangFlags []string, flag []string, cppCode bool) (
+	_ string, err error) {
 	defer func() {
 		if err != nil {
 			err = fmt.Errorf("Cannot get Include List : %v", err)
@@ -490,11 +606,18 @@ func getIncludeList(inputFiles, clangFlags []string, flag string, cppCode bool)
 			return
 		}
 	}
-	args = append(args, flag, "-c")
+	args = append(args, flag...)
+	args = append(args, "-c")
 	args = append(args, inputFiles...)
 	args = append(args, clangFlags...)
-	var cmd *exec.Cmd
 
+	defer func() {
+		if err != nil {
+			fmt.Errorf("used next arguments: `%v`. %v", args, err)
+		}
+	}()
+
+	var cmd *exec.Cmd
 	compiler, compilerFlag := Compiler(cppCode)
 	args = append(compilerFlag, args...)
 	cmd = exec.Command(compiler, args...)
@@ -506,5 +629,9 @@ func getIncludeList(inputFiles, clangFlags []string, flag string, cppCode bool)
 		err = fmt.Errorf("preprocess failed: %v\nStdErr = %v", err, stderr.String())
 		return
 	}
-	return parseIncludeList(out.String())
+
+	// add stderr to out, for flags "-MM -H"
+	out.WriteString(stderr.String())
+
+	return out.String(), err
 }
diff --git a/program/definition_function.go b/program/definition_function.go
index 8bb99e6..060c1b4 100644
--- a/program/definition_function.go
+++ b/program/definition_function.go
@@ -19,6 +19,11 @@ type DefinitionFunction struct {
 	// to represent a varargs.
 	ArgumentTypes []string
 
+	// Each function from some source. For example: "stdio.h"
+	IncludeFile string
+	// If function called, then true.
+	IsCalled bool
+
 	// If this is not empty then this function name should be used instead
 	// of the Name. Many low level functions have an exact match with a Go
 	// function. For example, "sin()".
@@ -515,3 +520,27 @@ func (p *Program) loadFunctionDefinitions() {
 		}
 	}
 }
+
+func (p *Program) SetCalled(name string) {
+	f, ok := p.functionDefinitions[name]
+	if ok {
+		f.IsCalled = true
+		p.functionDefinitions[name] = f
+	}
+}
+
+func (p *Program) GetOutsideCalledFunctions() (ds []DefinitionFunction) {
+	for _, v := range p.functionDefinitions {
+		if v.IncludeFile == "" {
+			continue
+		}
+		if p.PreprocessorFile.IsUserSource(v.IncludeFile) {
+			continue
+		}
+		if !v.IsCalled {
+			continue
+		}
+		ds = append(ds, v)
+	}
+	return
+}
diff --git a/transpiler/bind.go b/transpiler/bind.go
new file mode 100644
index 0000000..dee1478
--- /dev/null
+++ b/transpiler/bind.go
@@ -0,0 +1,204 @@
+package transpiler
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+
+	goast "go/ast"
+	"go/format"
+	"go/token"
+
+	"github.com/Konstantin8105/c4go/program"
+	"github.com/Konstantin8105/c4go/types"
+)
+
+func generateBinding(p *program.Program) (bindHeader, bindCode string) {
+	// outside called functions
+	ds := p.GetOutsideCalledFunctions()
+	if len(ds) == 0 {
+		return
+	}
+
+	// automatic binding of function
+	{
+		in := map[string]bool{}
+		for i := range ds {
+			in[p.PreprocessorFile.GetBaseInclude(ds[i].IncludeFile)] = true
+		}
+		for header := range in {
+			bindHeader += fmt.Sprintf("// #include <%s>\n", header)
+		}
+		bindHeader += "import \"C\"\n\n"
+	}
+
+	for i := range ds {
+		//
+		// Example:
+		//
+		// // #include <stdlib.h>
+		// // #include <stdio.h>
+		// // #include <errno.h>
+		// import "C"
+		//
+		// func Seed(i int) {
+		//   C.srandom(C.uint(i))
+		// }
+		//
+
+		// input data:
+		// {frexp double [double int *] true true  [] []}
+		//
+		// output:
+		// func  frexp(arg1 float64, arg2 []int) float64 {
+		//		return float64(C.frexp(C.double(arg1), unsafe.Pointer(arg2)))
+		// }
+
+		mess := p.GenerateWarningMessage(fmt.Errorf(
+			"Add c-binding for implementate function : `%s`", ds[i].Name), nil)
+		bindCode += mess + "\n"
+
+		code, err := getBindFunction(p, ds[i])
+		if err != nil {
+			bindCode += p.GenerateWarningMessage(err, nil) + "\n"
+			continue
+		}
+		index := strings.Index(code, "\n")
+		if index < 0 {
+			continue
+		}
+		bindCode += code[index:] + "\n"
+	}
+
+	return
+}
+
+func getBindFunction(p *program.Program, d program.DefinitionFunction) (code string, err error) {
+	var f goast.FuncDecl
+	f.Name = goast.NewIdent(d.Name)
+
+	prefix := "arg"
+	// arguments types
+	var ft goast.FuncType
+	var fl goast.FieldList
+	var argResolvedType []string
+	for i := range d.ArgumentTypes {
+		resolveType, err := types.ResolveType(p, d.ArgumentTypes[i])
+		if err != nil {
+			return "", fmt.Errorf("cannot generate argument binding function `%s`: %v", d.Name, err)
+		}
+		fl.List = append(fl.List, &goast.Field{
+			Names: []*goast.Ident{goast.NewIdent(fmt.Sprintf("%s%d", prefix, i))},
+			Type:  goast.NewIdent(resolveType),
+		})
+		argResolvedType = append(argResolvedType, resolveType)
+	}
+	ft.Params = &fl
+	f.Type = &ft
+	// return type
+	var fr goast.FieldList
+	ft.Results = &fr
+	var returnResolvedType string
+	if d.ReturnType != "" {
+		resolveType, err := types.ResolveType(p, d.ReturnType)
+		if err != nil {
+			return "", fmt.Errorf("cannot generate return type binding function `%s`: %v", d.Name, err)
+		}
+		fr.List = append(fr.List, &goast.Field{
+			Type: goast.NewIdent(resolveType),
+		})
+		returnResolvedType = resolveType
+	}
+
+	// create body
+	var arg []goast.Expr
+	for i := range argResolvedType {
+		// convert from Go type to Cgo type
+		cgoExpr, err := ResolveCgoType(p, argResolvedType[i], goast.NewIdent(fmt.Sprintf("%s%d", prefix, i)))
+		if err != nil {
+			return "", fmt.Errorf("cannot resolve cgo type for function `%s`: %v", d.Name, err)
+		}
+
+		arg = append(arg, cgoExpr)
+	}
+
+	f.Body = &goast.BlockStmt{
+		List: []goast.Stmt{
+			&goast.ReturnStmt{
+				Results: []goast.Expr{
+					&goast.CallExpr{
+						Fun: goast.NewIdent(returnResolvedType),
+						Args: []goast.Expr{
+							&goast.CallExpr{
+								Fun:  goast.NewIdent(fmt.Sprintf("C.%s", d.Name)),
+								Args: arg,
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	var buf bytes.Buffer
+	if err := format.Node(&buf, token.NewFileSet(), &goast.File{
+		Name:  goast.NewIdent("main"),
+		Decls: []goast.Decl{&f},
+	}); err != nil {
+		return "", fmt.Errorf("cannot get source of binding function : %s", d.Name)
+	}
+
+	return buf.String(), nil
+}
+
+func cgoTypes(goType string) (_ string, ok bool) {
+	goType = strings.TrimSpace(goType)
+	switch goType {
+	case "int":
+		return "int", true
+	case "float64":
+		return "double", true
+	}
+	return "", false
+}
+
+func ResolveCgoType(p *program.Program, goType string, expr goast.Expr) (a goast.Expr, err error) {
+	if ct, ok := cgoTypes(goType); ok {
+		return &goast.CallExpr{
+			Fun: &goast.SelectorExpr{
+				X:   goast.NewIdent("C"),
+				Sel: goast.NewIdent(ct),
+			},
+			Args: []goast.Expr{expr},
+		}, nil
+	}
+
+	if strings.Contains(goType, "[") {
+		// []int  -> * _Ctype_int
+		p.AddImport("unsafe")
+		t, ok := cgoTypes(goType[2:])
+		if ok {
+			t = "( * _Ctype_" + t + " ) "
+			return &goast.CallExpr{
+				Fun: goast.NewIdent(t),
+				Args: []goast.Expr{
+					&goast.CallExpr{
+						Fun: goast.NewIdent("unsafe.Pointer"),
+						Args: []goast.Expr{
+							&goast.UnaryExpr{
+								Op: token.AND,
+								X: &goast.IndexExpr{
+									X:      expr,
+									Lbrack: 1,
+									Index:  goast.NewIdent("0"),
+								},
+							},
+						},
+					},
+				},
+			}, nil
+		}
+	}
+
+	return nil, fmt.Errorf("cannot resolve to cgo type: `%s`", goType)
+}
diff --git a/transpiler/call.go b/transpiler/call.go
index e0c1e36..da16ebc 100644
--- a/transpiler/call.go
+++ b/transpiler/call.go
@@ -334,6 +334,10 @@ func transpileCallExpr(n *ast.CallExpr, p *program.Program) (
 	// defined is handled below (we haven't seen the prototype yet).
 	functionDef := p.GetFunctionDefinition(functionName)
 
+	if functionDef != nil {
+		p.SetCalled(functionName)
+	}
+
 	if functionDef == nil {
 		// We do not have a prototype for the function, but we should not exit
 		// here. Instead we will create a mock definition for it so that this
diff --git a/transpiler/transpiler.go b/transpiler/transpiler.go
index f154969..8714811 100644
--- a/transpiler/transpiler.go
+++ b/transpiler/transpiler.go
@@ -22,7 +22,9 @@ var AddOutsideStruct bool
 
 // TranspileAST iterates through the Clang AST and builds a Go AST
 func TranspileAST(fileName, packageName string, withOutsideStructs bool,
-	p *program.Program, root ast.Node) (err error) {
+	p *program.Program, root ast.Node) (
+	source string, // result Go source
+	err error) {
 	// Start by parsing an empty file.
 	p.FileSet = token.NewFileSet()
 	packageSignature := fmt.Sprintf("package %v", packageName)
@@ -31,7 +33,7 @@ func TranspileAST(fileName, packageName string, withOutsideStructs bool,
 	AddOutsideStruct = withOutsideStructs
 
 	if err != nil {
-		return err
+		return
 	}
 
 	// replace if type name and variable name
@@ -136,7 +138,25 @@ func TranspileAST(fileName, packageName string, withOutsideStructs bool,
 		p.File.Decls = append([]goast.Decl{importDecl}, p.File.Decls...)
 	}
 
-	return err
+	// generate Go source
+	source = p.String()
+
+	// checking implementation for all called functions
+	bindHeader, bindCode := generateBinding(p)
+	if len(bindCode) > 0 {
+		index := strings.Index(source, "package")
+		index += strings.Index(source[index:], "\n")
+		src := source[:index]
+		src += "\n"
+		src += bindHeader
+		src += "\n"
+		src += source[index:]
+		src += "\n"
+		src += bindCode
+		source = src
+	}
+
+	return
 }
 
 func transpileToExpr(node ast.Node, p *program.Program, exprIsStmt bool) (
@@ -460,6 +480,22 @@ func transpileToNode(node ast.Node, p *program.Program) (
 		return transpileTranslationUnitDecl(p, n)
 	}
 
+	if fd, ok := node.(*ast.FunctionDecl); ok {
+		if d := p.GetFunctionDefinition(fd.Name); d == nil ||
+			p.PreprocessorFile.IsUserSource(d.IncludeFile) {
+
+			// create new definition
+			if _, _, f, r, err := util.ParseFunction(fd.Type); err == nil {
+				p.AddFunctionDefinition(program.DefinitionFunction{
+					Name:          fd.Name,
+					ReturnType:    r[0],
+					ArgumentTypes: f,
+					IncludeFile:   p.PreprocessorFile.GetBaseInclude(fd.Position().File),
+				})
+			}
+		}
+	}
+
 	if !AddOutsideStruct {
 		if node != nil {
 			if !p.PreprocessorFile.IsUserSource(node.Position().File) {
diff --git a/travis/ed.sh b/travis/ed.sh
index c74d9f0..535a47d 100755
--- a/travis/ed.sh
+++ b/travis/ed.sh
@@ -26,6 +26,7 @@ go build
 
 # tranpilation
 $C4GO transpile  -cpuprofile=./testdata/cpu.out              \
+				 -s                                          \
 	             -o="$TEMP_FOLDER/$VERSION.go"               \
 				 -clang-flag="-DPROGVERSION=\"$VERSION\""    \
 				 $TEMP_FOLDER/$VERSION/$VERSION/*.c


Test patch:
diff --git a/main_test.go b/main_test.go
index 7b802f2..a4820d8 100644
--- a/main_test.go
+++ b/main_test.go
@@ -83,15 +83,21 @@ func TestIntegrationScripts(t *testing.T) {
 			}
 
 			// slice of program results
-			progs := [2]func(string, string, string, []string) (string, error){
+			progs := [2]func(string, string, string, []string, []string) (string, error){
 				runC,
 				runGo,
 			}
 
 			var results [2]string
+			var clangFlags []string
+
+			// specific of binding
+			if strings.Contains(file, "bind.c") {
+				clangFlags = append(clangFlags, "-Itests/bind/bind.h")
+			}
 
 			for i := 0; i < len(progs); i++ {
-				out, err := progs[i](file, subFolder, stdin, args)
+				out, err := progs[i](file, subFolder, stdin, clangFlags, args)
 				if err != nil {
 					t.Fatalf("Error for function %d : %v", i, err)
 					return
@@ -176,7 +182,7 @@ func TestIntegrationScripts(t *testing.T) {
 }
 
 // compile and run C code
-func runC(file, subFolder, stdin string, args []string) (string, error) {
+func runC(file, subFolder, stdin string, clangFlags, args []string) (string, error) {
 	cFileName := "a.out"
 	cPath := subFolder + cFileName
 
@@ -184,9 +190,13 @@ func runC(file, subFolder, stdin string, args []string) (string, error) {
 		strings.HasSuffix(file, "cpp"))
 
 	// Compile C.
-	out, err := exec.Command(
-		compiler, append(compilerFlag, "-lm", "-o", cPath, file)...).
-		CombinedOutput()
+	var seq []string
+	seq = append(seq, compilerFlag...)
+	seq = append(seq, "-lm")
+	seq = append(seq, "-o", cPath)
+	seq = append(seq, clangFlags...)
+	seq = append(seq, file)
+	out, err := exec.Command(compiler, seq...).CombinedOutput()
 	if err != nil {
 		return "", fmt.Errorf("Cannot compile : %v\n%v", err, string(out))
 	}
@@ -345,11 +355,12 @@ func TestApp(t *testing.T) {
 }
 
 // compile and run Go code
-func runGo(file, subFolder, stdin string, args []string) (string, error) {
+func runGo(file, subFolder, stdin string, clangFlags, args []string) (string, error) {
 
 	programArgs := DefaultProgramArgs()
 	programArgs.inputFiles = []string{file}
 	programArgs.outputFile = subFolder + "main.go"
+	programArgs.clangFlags = clangFlags
 	if strings.HasSuffix(file, "cpp") {
 		programArgs.cppCode = true
 	}
diff --git a/preprocessor/preprocessor_test.go b/preprocessor/preprocessor_test.go
index 6ca7a60..06949e3 100644
--- a/preprocessor/preprocessor_test.go
+++ b/preprocessor/preprocessor_test.go
@@ -10,7 +10,7 @@ func TestNewFilePPFail(t *testing.T) {
 }
 
 func TestGetIncludeListFail(t *testing.T) {
-	_, err := getIncludeList([]string{"@sdf s"}, []string{"wqq4 `?p"}, "w3 fdws", false)
+	_, err := getIncludeList([]string{"@sdf s"}, []string{"wqq4 `?p"}, []string{"w3 fdws", "sdfsr 4"}, false)
 	if err == nil {
 		t.Fatalf("Haven`t error")
 	}
diff --git a/tests/bind.c b/tests/bind.c
new file mode 100644
index 0000000..b2df851
--- /dev/null
+++ b/tests/bind.c
@@ -0,0 +1,29 @@
+#include "tests.h"
+#include <stdio.h>
+
+#define START_TEST(t) \
+    diag(#t);         \
+    test_##t();
+
+
+// outside C header
+#include "bind/bind.h"
+
+void test_int()
+{
+	int i = 12;
+	is_eq(i,12);
+	i = bind_int(i);
+	is_eq(i,42);
+	bind_int_pnt(&i);
+	is_eq(i,12);
+}
+
+int main()
+{
+    plan(3);
+
+	START_TEST(int);
+
+    done_testing();
+}
diff --git a/tests/bind/bind.h b/tests/bind/bind.h
new file mode 100644
index 0000000..4a3afbb
--- /dev/null
+++ b/tests/bind/bind.h
@@ -0,0 +1,9 @@
+int  bind_int    (int  i)
+{
+	return i + 30;
+}
+
+void bind_int_pnt(int *i)
+{
+	*i -= 30;
+}
diff --git a/tests/math.c b/tests/math.c
index 78fe779..4c6ec4b 100644
--- a/tests/math.c
+++ b/tests/math.c
@@ -12,7 +12,7 @@ unsigned long long ullmax = 18446744073709551615ull;
 
 int main()
 {
-    plan(491);
+    plan(493);
 
     double w1 = 100;
     double w2 = 2;
@@ -769,5 +769,16 @@ int main()
     is_eq(erff(1.0f), 1.0f - erfcf(1.0f));
     is_eq(erfl(1.0), 1 - erfcl(1.0));
 
+
+	diag("frexp");
+	{
+		int n;
+		double param = 8.0, result;
+		result = frexp(param,&n);
+		is_eq(result, 0.5000);
+		is_eq(n     , 4);
+	}
+
+
     done_testing();
 }
diff --git a/travis/test.sh b/travis/test.sh
index d5b56e8..17e7b01 100755
--- a/travis/test.sh
+++ b/travis/test.sh
@@ -15,7 +15,8 @@ export PKGS_DELIM=$(echo "$PKGS" | tr ' ' ',')
 echo "PKGS       : $PKGS"
 echo "PKGS_DELIM : $PKGS_DELIM"
 
-go test -v -cover -tags integration     \
+go test -v -cover -timeout=30m          \
+				  -tags integration     \
 	              -coverpkg=$PKGS_DELIM \
 				  -coverprofile=./testdata/pkg.coverprofile $PKGS