I'm trying to build existed Go package into C shared library and header using CGO.
I built the package with -buildmode c-shared as documented.
-buildmode=c-shared
Build the listed main package, plus all packages it imports,
into a C shared library. The only callable symbols will
be those functions exported using a cgo //export comment.
Requires exactly one main package to be listed
And used //export Func to expose functions as C symbols.
All //export functions in main package are exported properly. However when I moved those functions to sub-package (with //export), those functions are not exported. I imported the sub-package in main package, too.
Here's my code.
main.go
package main
import "C"
import (
"fmt"
_ "github.com/onosolutions/archanan-cgo/c"
"math/rand"
)
// FuncInMain generates a random integer.
//export FuncInMain
func FuncInMain(max C.int) C.int {
return C.int(rand.Intn(int(max)))
}
func main() {
fmt.Printf("Hello World %d!\n", int(FuncInMain(256)))
}
c/c.go
package c
import "C"
import (
"math/rand"
)
// FuncInSubPackage generates a random integer.
//export FuncInSubPackage
func FuncInSubPackage(max C.int) C.int {
return C.int(rand.Intn(int(max)))
}
Then only FuncInMain is exported.
I read through CGO documentation, but there's nothing saying about exporting in sub-packages. The only clue I got is through go help buildmode, but it said that all imported sub-packages will be compiled. I'm not sure whether it isn't supported or I missed some configurations.
I'd love to achieve that to be able to modularize //export functions.
Both of them have own C.type, so as far as I know, there's no way to import function with C.type but using linking.
I didn't tried, but give it a chance:
import _ "unsafe"
//go:linkname FuncInSubPackage c.FuncInSubPackage
//export FuncInSubPackage
func FuncInSubPackage(max C.int) C.int
Related
I could override the builtin print() function's behavior by defining another print() in scope, as in https://play.golang.org/p/Y2ly31oXU67
Is it possible in go to alter the behavior on-the-fly of an imported function, say fmt.Println()?
If you want to 'alter' a builtin function, look at the very fine monkey patch utility https://github.com/bouk/monkey (And pay attention to the warnings, it's only really useful in test functions, and I for one reject any prod code that imports that package)
Import a different package with name "fmt" and implement whatever functions you need in that package. Here's an example:
File go.mod:
module test
File main.go
package main
import (
"test/fmt"
)
func main() {
fmt.Println("Hello, playground")
}
File fmt/fmt.go:
package fmt
import (
"fmt"
"log"
)
func Println(format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
log.Printf(msg)
}
Run it on the playground.
The code in this answer does not modify the imported function as asked in the question.
I am attempting to do a local import but it fails.
My environment is:
echo $GOPATH
/home/peter/go
echo $GOROOT
/usr/local/go
The entry point is:
/home/peter/go/src/projects/pkgs1/main.go
The imported file is:
/home/peter/go/src/projects/pkgs2/stuff.go
main.go
package main
import (
"fmt"
"projects/pkgs2" // <- this does not resolve
)
func main(){
fmt.Println("123")
pkgs2.X()
}
stuff.go
package pkgs2
import "fmt"
func X(){
fmt.Println("X")
}
Any pointers on what I do wrong?
Your import path is correct and should resolve successfully, but as written, your program won't compile because the import isn't being used and there is no local function named x.
As mentioned by mkopriva your x function in pkgs2 isn't exported and you have not qualified it when trying to use it in your main package.
To export a function, it needs to start with a capital letter.
To use the function in another package, you need to prefix the package name to the function name.
main.go
package main
import (
"fmt"
"projects/pkgs2"
)
func main(){
fmt.Println("123")
pkgs2.X()
}
stuff.go
package pkgs2
import "fmt"
func X(){
fmt.Println("X")
}
In Go, I have a compile error due to incompatible types which I cannot explain. I'm using the "C" module. A minimum example consists of the following 2 files:
package module
import "C"
type T struct {
X C.int
}
and a main program
package main
import (
"fmt"
"sandbox/module"
)
import "C"
func f() *module.T {
var x C.int = 42
return &module.T{X: x}
}
func main() {
fmt.Printf("value: %d", f().X)
}
This fails to compile with the message
./main.go:12: cannot use x (type C.int) as type module.C.int in field value.
For some reason the compiler thinks that C.int is not equal to module.C.int.
It must have something to do with the C module and the fact that the code is spread across 2 modules because it suddenly works if I switch from C.int to plain int.
Why does this piece of code not compile? What would be the proper solution to make it compile without squashing all code together in one module?
I'm using the latest Go compiler 1.9.2 on Ubuntu 16.04.
Command cgo
Go references to C
Cgo translates C types into equivalent unexported Go types. Because
the translations are unexported, a Go package should not expose C
types in its exported API: a C type used in one Go package is
different from the same C type used in another.
You say, "For some reason the compiler thinks that C.int is not equal to module.C.int." As the cgo command documentation explains, unexported Go types in different packages are not equal.
Don't expose C types in an exported API. For example,
module.go:
package module
type T struct {
X int
}
main.go:
package main
import (
"fmt"
"sandbox/module"
)
import "C"
func f() *module.T {
var x C.int = 42
return &module.T{X: int(x)}
}
func main() {
fmt.Printf("value: %d\n", f().X)
}
Output:
value: 42
I have created a library by the name libfastget which is in the src with my program as
src
|-libfastget
| |-libfastget.go
|
|-MainProgram
|-main.go
and the libfastget exports a funtion fastget as follows
package libfastget
import (
"fmt"
"io"
)
func fastget(urlPtr *string, nPtr *int, outFilePtr *string) download {
.....
return dl
}
When I use the library in my main program
package main
import (
"fmt"
"net/http"
"os"
"libfastget"
"path/filepath"
"strings"
"flag"
"time"
)
func uploadFunc(w http.ResponseWriter, r *http.Request) {
n:=libfastget.fastget(url,4,filename)
}
}
I get the following error upon trying to build with go build
# FServe
./main.go:94: cannot refer to unexported name libfastget.fastget
./main.go:94: undefined: libfastget.fastget
The strange thing is that the library file libfastget.a is present in the pkg folder.
you would need to make your function exportable with an uppercase for its name:
func Fastget(...
Used as:
n:=libfastget.Fastget(url,4,filename)
The spec mentions: "Exported identifiers":
An identifier may be exported to permit access to it from another package. An identifier is exported if both:
the first character of the identifier's name is a Unicode upper case letter (Unicode class "Lu"); and
the identifier is declared in the package block or it is a field name or method name.
All other identifiers are not exported.
to export a function into another package the function identifier must start with a capital letter.
I recently started learning GO Lang (2 days back)
And what I found was you need to setup a workspace folder to make the local packages import into other projects or main.go files. I'm using VS Code editor. Please correct me if Im wrong, but this setup works fine for me.
Inside your bash_profile OR .zshrc file add below lines, update the GOPATH as per your folder path.
export GOPATH=~/projects/GO_PROJECTS
export PATH=$PATH:$GOPATH/bin:$PATH
and this is my sayHello.go file, please note to be able to export a function the func name should start with a CapitalCase SayHello
package utils
import "fmt"
func SayHello() {
fmt.Println("Hello, Ajinkya")
}
and now I am able to import utils package into main.go file
package main
import (
"go_proj1/utils"
)
func main() {
utils.SayHello()
}
set the current directory as GOPATH
or you can use local import as follows
move your main.go to the ../ directory to the libfastget.go.
i mean the files looks like:
src
|-libfastget
| |-libfastget.go
|
|-main.go
import "./libfastget"
I have a Go project at $GOPATH/dalu/myproject with the following files :
main.go:
package main
import "dalu/myproject/subpackage"
var GV string = "World"
func main() {
subpackage.Hello()
}
subpackage/subpackage.go:
package subpackage
import (
"fmt"
"dalu/myproject"
)
func Hello() {
//? fmt.Println("Hello"+GV)
}
Bonus (if I could):
I tried something similar with more subpackages and when trying to import a subpackage in main that imports another subpackage which imports the first mentioned subpackage I get "import cycle not allowed"
As the compiler so nicely said, Go doesn't allow cyclic dependencies, and unlike C++ there are no forward declarations tricks to be done here.
if you have a state where:
A imports B AND B imports A
it measns you need to move whatever they share between them to package C, and do:
A imports B, C AND B imports C
and everyone's happy!
or in your example, add a file called dalu/myproject/gv/gv.go and in it define this GV. Then import it in both main and subpackage