好吧,我做了这个玩具:
sql_conn.c:
// https://dev.mysql.com/doc/refman/8.0/en/mysql-real-connect.html
// http://zetcode.com/db/mysqlc/
#include <stdio.h>
#include <stdlib.h>
#include <caml/mlvalues.h>
#include <mysql/mysql.h>
CAMLprim value connect(value dbname, value dbuser, value dbpassword){
MYSQL *con = mysql_init(NULL);
mysql_real_connect(con,"localhost",String_val(dbuser), String_val(dbpassword),String_val(dbname),0,NULL,0);
return (value) con;
}
CAMLprim value print_query(value con, value tbl, value field, value constraint){
char query[100];
sprintf(query, "select * from %s where %s='%s';",(char *) tbl,(char *) field,(char *) constraint);
mysql_query((MYSQL*) con, query);
MYSQL_RES *result = mysql_store_result((MYSQL*) con);
int num_fields = mysql_num_fields(result);
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
for(int i = 0; i < num_fields; i++)
{
printf("%s ", row[i] ? row[i] : "NULL");
}
printf("\n");
}
mysql_free_result(result);
return Val_unit;
}
main.ml:
type dbconn
external print_query: dbconn -> string -> string -> string -> unit = "print_query"
external connect: string -> string -> string -> dbconn = "connect"
let database = "dogs";;
let user = "root";;
let pwd = "kafka";;
let tbl = "dogs";;
let field = "Name";;
let arg = "reximus";;
let db = connect database user pwd;;
print_query db tbl field arg;;
生成文件
main:
g++ -c sql_conn.c -lmysqlclient
ocamlopt main.ml
./a.out
连接(...)有效,但我收到错误:
g++ -c sql_conn.c -lmysqlclient
ocamlopt main.ml
main.o: In function `camlMain__entry':
main.ml:(.text+0x89): undefined reference to `print_query'
main.o: In function `camlMain__6':
main.ml:(.data+0xa8): undefined reference to `print_query'
collect2: error: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking
Makefile:2: recipe for target 'main' failed
make: *** [main] Error 2
在制作上。任何指针赞赏。它说问题在于链接,但是当唯一的方法是连接(...)时,它工作正常。我不是一个经验丰富的C程序员(如果你不能告诉),所以也许我错过了一些明显的东西。任何指针都赞赏。
谢谢你的时间!
另外,像这样的帖子是否也应该用mysql标记?
答案 0 :(得分:2)
首先,您没有收到connect
的错误消息,因为已经有connect
function in the standard library。我强烈建议重命名你的函数,因为mysql_real_connect
可能在内部使用标准connect
,如果你这样覆盖它会导致无限递归。
如果您使用的是本机代码编译器
ocamlopt
,则不需要-custom
标志,因为ocamlopt
的最终链接阶段始终构建独立的可执行文件。要构建混合的OCaml / C可执行文件,请执行ocamlopt
命令:
- 所需OCaml原生对象文件(
.cmx
和.cmxa
文件)的名称;- 实现所需基元的C对象文件和库(
.o
,.a
,.so
或.dll
文件)的名称。
ocamlopt
命令的命令行界面非常接近ocamlc
的命令行界面。它接受相同类型的参数,并在处理完所有选项后按顺序处理它们:[...]
以
.cmx
结尾的参数被视为编译对象代码。这些文件与通过编译.ml
参数(如果有)获得的目标文件以及OCaml标准库链接在一起,以生成本机代码可执行程序。 [...]以
.c
结尾的参数传递给C编译器,后者生成.o
/.obj
目标文件。该目标文件与程序链接。
后来:
-cclib -llibname
的
将-llibname
选项传递给链接器。这会导致给定的C库与程序链接。
免责声明:我还没有真正测试过以下步骤。这正是我认为通过阅读文档会有意义的。
由此我假设正确的编译命令看起来像
ocamlopt sql_conn.c main.ml -cclib -lmysqlclient
或者在Makefile中:
a.out: sql_conn.c main.ml
ocamlopt sql_conn.c main.ml -cclib -lmysqlclient
(如果您想添加同时执行该文件的main
目标,我会做
.PHONY: main
main: a.out
./a.out
)
如果您想分开这些步骤,它将如下所示:
将sql_conn.c
编译为sql_conn.o
:
gcc -c sql_conn.c
将main.ml
编译为main.cmx
(以及其他内容):
ocamlopt -c main.ml
将它们链接到一个可执行文件中:
ocamlopt sql_conn.o main.cmx -cclib -lmysqlclient
或者以Makefile形式:
sql_conn.o: sql_conn.c
gcc -c sql_conn.c
main.cmx: main.ml
ocamlopt -c main.ml
a.out: sql_conn.o main.cmx
ocamlopt sql_conn.o main.cmx -cclib -lmysqlclient
您的命令出现问题:
g++ -c sql_conn.c -lmysqlclient
g++
选择C ++编译器并准备与C ++标准库链接。 -lmysqlclient
将mysqlclient
库添加到集合中。
但-c
告诉它不要执行链接步骤(因此忽略C ++标准库和mysqlclient
),文件名(以.c
结尾)使其切换到C编译器。
整件事情等同于
gcc -c sql_conn.c
这会生成sql_conn.o
(包含已编译C代码的对象文件)。
ocamlopt main.ml
这告诉ocamlopt
编译main.ml
,将其与标准OCaml库链接,并生成一个名为a.out
的可执行文件。没有什么可以告诉它查看sql_conn.o
,因此该文件被忽略。
您在此处收到链接器错误,因为找不到print_query
(它在sql_conn.o
中定义)。如上所述,您没有收到connect
的错误,因为系统库中已存在该名称的符号(尽管签名不兼容,但链接器不知道)。