ocamlopt: ошибка при соединении - PullRequest
0 голосов
/ 30 апреля 2018

Ну, я сделал эту игрушку:

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

На постройке. Любые указатели приветствуются. В нем говорится, что проблема связана со связыванием, но когда единственным методом было соединение (...), оно работало нормально. Я не опытный программист C (если вы не могли бы сказать), поэтому, возможно, я упускаю что-то очевидное. Любые указатели приветствуются.

Спасибо за ваше время!

Кроме того, должен ли такой пост также быть помечен mysql?

1 Ответ

0 голосов
/ 30 апреля 2018

Во-первых, вы не получите сообщение об ошибке для connect, поскольку в стандартной библиотеке уже есть функция connect. Я настоятельно рекомендую переименовать вашу функцию, потому что mysql_real_connect, вероятно, использует стандарт connect для внутреннего использования, и это приведет к бесконечной рекурсии, если вы переопределите его следующим образом.


Цитирование из Руководство OCaml :

Если вы используете компилятор собственного кода ocamlopt, флаг -custom не требуется, так как последний этап связывания ocamlopt всегда создает автономный исполняемый файл. Чтобы создать смешанный исполняемый файл OCaml / C, выполните команду ocamlopt с:

  • имена нужных собственных объектных файлов OCaml (.cmx и .cmxa файлы);
  • имена объектных файлов и библиотек C (.o, .a, .so или .dll файлов), которые реализуют необходимые примитивы.

А также :

Команда ocamlopt имеет интерфейс командной строки, очень близкий к интерфейсу ocamlc. Он принимает те же типы аргументов и обрабатывает их последовательно после обработки всех опций:

[...]

  • Аргументы, заканчивающиеся на .cmx, считаются скомпилированным объектным кодом. Эти файлы связаны друг с другом, вместе с объектными файлами, полученными путем компиляции аргументов .ml (если есть), и стандартной библиотекой OCaml для создания исполняемой программы с собственным кодом. [...]

  • Аргументы, заканчивающиеся на .c, передаются компилятору C, который генерирует объектный файл .o / .obj. Этот объектный файл связан с программой.

и позже:

-cclib -l<i>libname</i>
Передайте параметр -l<i>libname</i> компоновщику. Это приводит к тому, что данная библиотека 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.c в sql_conn.o:

    gcc -c sql_conn.c
    
  2. Компиляция main.ml в main.cmx (среди прочего):

    ocamlopt -c main.ml
    
  3. Свяжите их вместе в исполняемый файл:

    ocamlopt sql_conn.o main.cmx -cclib -lmysqlclient
    

Или в форме Makefile:

1114 * *

Проблемы с вашими командами:

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, поскольку символ этого имени (хотя и с несовместимой подписью, но компоновщик не знает об этом) уже существует в системной библиотеке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...