簡體   English   中英

ocamlopt:鏈接期間出錯

[英]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

如果要分離這些步驟,則如下所示:

  1. 編譯sql_conn.csql_conn.o

     gcc -c sql_conn.c 
  2. 編譯main.mlmain.cmx (除其他事項外):

     ocamlopt -c main.ml 
  3. 將它們鏈接到一個可執行文件中:

     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 ++標准庫鏈接。 -lmysqlclientmysqlclient庫添加到集合中。

但是-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM