CGO undefined reference to `TIFFGetField' - c

I am mostly working on Go projects atm, but I have to use CGO for part of my project on the purpose of editing TIF files from Go with C, because of parameter pass-through. I am not familiar with C, but it seems the only way to solve our problem.
The problem is when I theoretically set up the Go part, and wanted to use my C code, it drops undefined reference to xxxx'` with TIFFGetField,_TIFFmalloc,TIFFReadRGBAImage function calls.
Probably I am not even importing the libtiff libary in the right way.
The funny thing is the first code of the C code itself is TIFF* tif = TIFFOpen("foo.tif", "w"); does not have reference error to TIFFOpen, only the others (TIFFGetField,_TIFFmalloc,TIFFReadRGBAImage,_TIFFfree,TIFFClose)
my go code is
package main
// #cgo CFLAGS: -Ilibs/libtiff/libtiff
// #include "tiffeditor.h"
import "C"
func main() {
C.tiffEdit()
}
#include "tiffeditor.h"
#include "tiffio.h"
void tiffEdit(){
TIFF* tif = TIFFOpen("foo.tif", "w");
if (tif) {
uint32 w, h;
size_t npixels;
uint32* raster;
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
npixels = w * h;
raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32));
if (raster != NULL) {
if (TIFFReadRGBAImage(tif, w, h, raster, 0)) {
//
}
_TIFFfree(raster);
}
TIFFClose(tif);
}
}
My goal on first is just to establish libtiff with my go code and make it to recognise the functions libtiff, so I can focus on solving the problem itself.

If you see the message "undefined reference to xxx" in cgo. It is very likely that you're missing the linking to the shared library.
I'm not quite familiar to this package, but i suggest you could try add something as below to make your program link to the C dynamic library:
// #cgo LDFLAGS: -lyour-lib
In case above, i link my go program to a C dynamic library called "libyour-lib.so".
Example
Assumed that your TIFF source comes from http://www.simplesystems.org/libtiff/
Steps
Download the source codes
Check README.md (or INSTALL) to read the guide about how to compile this C library
Follows provided instructions and install the C library
If you're doing correctly without modifying default settings, you should find tiff headers in /usr/local/include and its dynamic libraries in /usr/local/lib
Integrates these stuffs to your go program by having proper hints for cgo compiler.
Codes
I've build this program successfully, and executed as expected. It might be a good starting point for you.
package main
// #cgo LDFLAGS: -ltiff
// #include "tiffio.h"
// #include <stdlib.h>
import "C"
import (
"fmt"
"unsafe"
)
func main() {
path, perm := "foo.tif", "w"
// Convert Go string to C char array. It will do malloc in C,
// You must free these string if it no longer in use.
cpath := C.CString(path)
cperm := C.CString(perm)
// Defer free the memory allocated by C.
defer func() {
C.free(unsafe.Pointer(cpath))
C.free(unsafe.Pointer(cperm))
}()
tif := C.TIFFOpen(cpath, cperm)
if tif == nil {
panic(fmt.Errorf("cannot open %s", path))
}
C.TIFFClose(tif)
}

Related

undefined reference to `__imp_CreateSolidBrush'

Trying to use CreateSolidBrush to change a window background color.
I've included wingdi.h, I believe I've linked gdi32.lib ( however I converted gdi32.lib to a gdi32.a by using LIB2A, and I wonder if this may be an issue? ).
I wouldn't mind using another function but I worry this could be come a re-occuring issue if I'm not able to find a solution.
Some relevant code:
#include <stdio.h>
#include <windows.h>
#include <wingdi.h>
#include <main.h>
DWORD CreateMainWindow(void)
{
.............
WNDCLASSEXA WindowClass = { 0 };
WindowClass.hbrBackground = CreateSolidBrush(RGB(200, 200, 200));
.............
}
I use a function to easily compile
int Compile()
{
................
int result = 0;
char *include = "C:\\Users\\Coding\\C\\src\\include";
char *link = "C:\\Users\\Coding\\C\\src\\lib";
char command[256];
if(snprintf(
command,
sizeof(command),
"gcc -o main -I%s -l gdi32 -L%s main.c", include, link) >= sizeof(command))
{
//exception catching and handling
}
else
{
system(command);
}
return result;
}
I have no reason to believe the file isn't being linked as I'm not receiving an error.
Also I'm only using Notepad++, mingw64, and command prompt.
The error is a linker error, because it can't find the shared library symbol CreateSolidBrush.
All that is needed is linker flag -lgdi32, so it links with MinGW's libgdi32.a.
Don't try to generate this file by converting it from some other file you found which is probably built with a totally different compiler. If you already experimented with that make sure to clean up any lingering gdi32 .a or .lib files from your previous attempts.
Well the answer was extremely simple, linkages and includes must come after the file.
C:\User> gcc main.c -lgdi32 -I<include path> -o main
If this was obvious then I apologize, hopefully this helps another confused individual

Add python modules to cython for use in c

I am currently trying to write a plugin backend in c by using .so files. Doing this in c works as I expect it to. However I thought about writing python plugins for my backend. Here is when i stumbled upon cython which seems to be very promising.
My backend is calling a function within the .so files and expects a value in return.
This function currently looks like this:
cdef public size_t transform_data(char *plugin_arguments, char **buffer):
printf("Entered function\n")
print("test\n")
printf("Test passed\n")
return 5
The interesting part is, that the printf works just fine. However the print doesn't. I suspect this is because there is some sort of linking error to a python module that I am missing? Also later on I would like to be able to add any python module to that file, for example the influxdb module. A call to influxdb.InfluxDBClient doesn't work either right now, I guess for the same reason that the print is not working.
I am compiling the file using
cythonize -3b some_plugin.pyx
and I have also tried to compile using a setup file that looks like this:
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("some_plugin.pyx"))
both resulting to a segfault as soon as I hit the print call.
Here is the code that I am using to call the .so file:
#include "execute_plugin.h"
#include <Python.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
size_t execute_plugin(char file_name[FILE_NAME_SIZE], char *plugin_arguments,
char **output_buffer) {
if (!Py_IsInitialized()) {
Py_SetPythonHome(L"/home/flo/.local/lib/python3.8");
Py_SetPath(L"/usr/lib/python3.8");
Py_Initialize();
}
if (!Py_IsInitialized())
return 0;
void *plugin;
size_t (*func_transform_data)(char *plugin_arguments, char **output_buffer);
char path[PATH_SIZE];
if (!get_path_to_file(path, PATH_SIZE)) {
printf("Could not receive the correct path to the plugin %s\n", file_name);
return 0;
}
plugin = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
if (!plugin) {
fprintf(stderr, "Error: %s\n", dlerror());
fprintf(stderr, "Cannot load %s\n", file_name);
return 0;
}
func_transform_data =
(size_t(*)(char *plugin_arguments, char **output_buffer))dlsym(
plugin, "transform_data");
if (!func_transform_data) {
fprintf(stderr, "Error: %s\n", dlerror());
dlclose(plugin);
return 0;
}
size_t length = func_transform_data(plugin_arguments, output_buffer);
printf("Size of answer is %ld\n", length);
dlclose(plugin);
Py_Finalize();
return length;
}
I have tried using the documentation and just copied the example: https://cython.readthedocs.io/en/latest/src/tutorial/embedding.html
In this example I didn't use an .so file but the .c and .h file that is also getting generated by the cythonize command. Interestingly enough the print function is working but as soon as I try to add another module like the influxdb module and try to call a function from it I also get errors.
Since I have not found a lot about using cython code in c I am wondering if what I am trying to do is even possible or if there is a better approach.
It's difficult to be certain what your issue is because you don't actually show how you call your Cython function. So what follows is a guess.
Cython does not produce standalone C functions. It produces functions that are part of a Python module and require that module to be initialized. What is probably happening is that Cython caches the lookup to the global print function as part of the module initialization. Since you skip the initialization the cached print function is not set up (hence the crash).
When you read the documentation, you'd have seen that all the examples ("Using Cython declarations from C" and "Embedding Cython modules...") import the module before using it. You must do this. The preferred way to do this is with PyImport_AppendInittab().
A second possibility is that you haven't initialized the Python interpreter. Again, this is not optional.

how to call c dll from latest lua 5.3

UPDATED: Problem solved. The dll must not be statically linking to lua, otherwise it crashes with a multiple Lua VMs detected exception. The code blow actually works fine, just leave it here in case someone got this problem too.
And wireshark uses lua5.2 because there's a "lua52.dll" in it's folder.
I'm writing wireshark plugin, some algorithm in C is difficult to implement in Lua, so I try to use these algorithm through dll.
Most examples online use the old version of Lua, which use luaL_register in the dll code. The luaL_register is replaced by lua_newtable/luaL_setfuncs in newer version, but I didn't find any working example online.
Here's what I tried :
#include <stdio.h>
#include <string.h>
#include "lua.hpp"
#include <windows.h>
extern "C" {
static int add(lua_State* L)
{
MessageBox(0, "", "", 0);
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 + op2);
return 1;
}
static luaL_Reg mylibs[] = {
{"add", add},
{0, 0}
};
__declspec(dllexport)
int luaopen_mylib(lua_State* L)
{
lua_newtable(L);
luaL_setfuncs(L, mylibs, 0);
lua_setglobal(L, "mylib");
return 1;
}
}
and the lua code:
require "mylib" -- <----------crashes
-- local mylib = package.loadlib("mylib.dll","luaopen_mylib");
print (mylib)
if(mylib)then
--mylib();
else
-- Error
end
local b=mylib.add(11,33);
print("sum:", b);
The lua code crashes at first line. How to fix it?
Another question, how to verify which version of Lua is wireshark using? Calling print(_VERSION) in wireshark's lua console, it shows nothing.
The crash occurs when statically linking to lua.lib, I guess there is already a lua VM in lua.lib, so use dynamic linking and the problem is gone.

Go cgo ldap_init could not determine kind of name for C.ldap_init

I was trying to learn and understand cgo.
I am writing a program in Go where I connect to AD and parse the output. I tested the code in C, which is working fine as expected. The relevant part in C is
char *ldap_host = "x.x.x.x";
int ldap_port = 389;
ldap = ldap_init(ldap_host, ldap_port))
Now I am trying to get the same working in go as
//#cgo CFLAGS: -lldap
//#include <ldap.h>
import "C"
func main() {
var hostname *string
hostname = &os.Args[1]
ldap_port := 389
ldap := C.ldap_init(*hostname, ldap_port)
}
But I am getting the following error
could not determine kind of name for C.ldap_init
What am I doing wrong here?
I would start by getting the basics of Go and cgo working before adding the individual peculiarities of a library like ldap. Some good starting points, especially the official cgo doc page.
https://golang.org/cmd/cgo/
http://blog.golang.org/c-go-cgo
https://github.com/golang/go/wiki/cgo
Starting from the top:
You don't need the CFLAGS here, but you will need LDFLAGS for the linker, and liblber for this to run.
#cgo LDFLAGS: -lldap -llber
You can't pass a pointer to a Go string as a C *char, they are different types. Strings in Go actually aren't addressable at all, so this would be a compile error if the build process got that far. Use C.CString, and C.free if you need to create C strings. You will also need to include stdlib.h for C.free.
url := C.CString(os.Args[1])
defer C.free(unsafe.Pointer(url))
Go's int size varies by architecture, and is not C's int type. ldap_port in your example is converted to the default type of int, where you would have needed C.int.
Finally, the original error in your question has nothing to do with Go or cgo. The ldap_init function is deprecated, and does not exist without setting LDAP_DEPRECATED. You should use the ldap_initialize function. Here is a minimal example that compiles:
package main
import (
"log"
"unsafe"
)
/*
#include <stdlib.h>
#include <ldap.h>
#cgo LDFLAGS: -lldap -llber
*/
import "C"
func main() {
url := C.CString("ldap://127.0.0.1:389/")
defer C.free(unsafe.Pointer(url))
var ldap *C.LDAP
rv := C.ldap_initialize(&ldap, url)
if rv != 0 {
log.Fatalf("ldap_initialize() error %d", rv)
}
log.Println("initialized")
}

R CMD SHLIB to create a DLL from a source .c file which needs an external library (on Windows x64)

First things first, I am very new to C programming and the whole idea of compilation, so I would really appreciate some very straightforward and step-by-step guidance on this.
Here is my problem: I am trying to write some C code that I can dyn.load into R to speed up my R task. My C code would involve some very complex matrix operation that is only available in an external library with the header file "matrix.h" and the static library file "matrix.lib". It would also make use of some basic R header files such as "Rdefines.h", etc. The files "matrix.h" and "matrix.lib" are located at C:\lcc\include and C:\lcc\lib, respectively. Here is a sample test C code:
#include <Rmath.h>
#include <R.h>
#include <Rdefines.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <matrix.h>
void foo(double *cdegree, double *fdegree, int *size) {
int i;
for(i=0; i<*size; i++) {
cdegree[i] = 5.0/9.0*(fdegree[i]-32.0);
}
}
As you can see, this is simple code converting Fahrenheit to Celsius. Although the test code does not make use of anything in the matrix library, the goal here is to be able to include both the R header files and matrix.h from the external library. If I try R CMD SHLIB this C code I get the "no such file or directory" error for trying to include "matrix.h". How can I tell R to compile this with the external library? Everything is done on a Windows 8.1 X64 system.
Honestly, you will find it much easier if you start exploring Rcpp. Here is a link to introduce you to Rcpp. There are many examples to be found throughout the documentation.
f2c.cpp
#include <Rcpp.h>
// [[Rcpp::export]]
void foo(Rcpp::NumericVector fdegree, Rcpp::NumericVector cdegree, int size){
int i;
for(i=0; i < size; i++){
cdegree[i] = 5.0/9.0*(fdegree[i]-32.0);
}
}
R code
library(Rcpp)
sourceCpp("f2c.cpp")
fdegree <- c(98.6, 212, 32)
cdegree <- c(0,0,0)
foo(fdegree, cdegree, length(fdegree))
cdegree
[1] 37 100 0
Naturally this makes some assumptions but it demonstrates how you can quickly use some C code and not fiddle with all the R headers and SHLIB.
Regarding your concern to use some external headers, just simply set the PKG_CXXFLAGS environmental variable to the location of your header(s).
Sys.setenv("PKG_CXXFLAGS" = '-I"path/to/headers"')
followed by the same compilation.
sourceCpp("f2c.cpp")
However, it should be noted that if you are doing more than a few of these functions you should build a package with Rcpp and provide an appropriate Makevars file. You can find further information on Rcpp package development here.

Resources