[英]ocamlopt: Error during linking
好吧,我做了這個玩具:
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;;
Makefile文件
main:
g++ -c sql_conn.c -lmysqlclient
ocamlopt main.ml
./a.out
和connect(...)工作,但我得到了錯誤:
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
在制造。 任何指針表示贊賞。 它說問題在於鏈接,但是當唯一的方法是connect(...)時,它工作正常。 我不是經驗豐富的C程序員(如果您不能說),所以也許我缺少明顯的東西。 任何指針表示贊賞。
謝謝你的時間!
另外,這樣的帖子也應該用mysql標記嗎?
首先,您不會因為connect
錯誤而出錯,因為標准庫中已經有一個connect
功能 。 我強烈建議重命名您的函數,因為mysql_real_connect
可能在內部使用標准connect
,如果您這樣覆蓋它,則會導致無限遞歸。
引用OCaml手冊 :
如果使用的是本機代碼編譯器
ocamlopt
,-custom
不需要-custom
標志,因為ocamlopt
的最后鏈接階段始終會構建獨立的可執行文件。 要構建混合的OCaml / C可執行文件,請使用以下命令執行ocamlopt
命令:
- 所需的OCaml本機目標文件的名稱(
.cmx
和.cmxa
文件);- 實現所需原語的C對象文件和庫(
.o
,.a
,.so
或.dll
文件)的名稱。
還有 :
ocamlopt
命令的命令行界面與ocamlc
非常接近。 它接受相同類型的參數,並在處理完所有選項后依次處理它們:[...]
以
.cmx
結尾的.cmx
被視為已編譯的目標代碼。 這些文件與通過編譯.ml
參數(如果有)獲得的目標文件以及OCaml標准庫鏈接在一起,以生成本機代碼可執行程序。 [...]以
.c
結尾的參數將傳遞給C編譯器,后者會生成.o
/.obj
對象文件。 該目標文件與程序鏈接。
然后:
-cclib -l
option to the linker . 將-l
選項傳遞給鏈接器。 這使給定的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
不會出錯,因為該名稱的符號(盡管具有不兼容的簽名,但鏈接器不知道)已存在於系統庫中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.