неопределенная ссылка только на некоторые функции math.h

У меня странная проблема.

Математические библиотеки были добавлены в мой make-файл.

# include standard C library
LDFLAGS += -lc
# include standard math library
LDFLAGS += -lm

и в выходном файле (.map) я вижу, что все было правильно связано:

LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/nof\libgcc.a
LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/../../../../powerpc-eabi/lib/nof\libc.a
LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/../../../../powerpc-eabi/lib/nof\libm.a

когда я делаю

z = pow((double) 2, (double) 3);

это работает нормально. Но если я проверю другую функцию, например:

double result = asin(x);

Я получу:

undefined reference to `asin'
collect2: ld returned 1 exit status

Как это может быть? оба pow и asin доступны в math.h, см. ниже:

/* Non reentrant ANSI C functions.  */

#ifndef _REENT_ONLY
#ifndef __math_6881
extern double acos _PARAMS((double));
extern double asin _PARAMS((double));
extern double atan2 _PARAMS((double, double));
extern double cosh _PARAMS((double));
extern double sinh _PARAMS((double));
extern double exp _PARAMS((double));
extern double ldexp _PARAMS((double, int));
extern double log _PARAMS((double));
extern double log10 _PARAMS((double));
extern double pow _PARAMS((double, double));
extern double sqrt _PARAMS((double));
extern double fmod _PARAMS((double, double));
#endif /* ! defined (__math_68881) */
#endif /* ! defined (_REENT_ONLY) */

как один может работать, а другой вызывать проблемы с компоновщиком? Если я запущу -nm на libm.a, я получу следующий результат: (извините за огромный объем, я скопировал только разделы со словом sin)

lib_a-e_asin.o:
         U __adddf3
         U __divdf3
         U __gtdf2
00000000 T __ieee754_asin
         U __ieee754_sqrt
         U __muldf3
         U __subdf3
         U fabs

lib_a-e_j0.o:
         U __adddf3
         U __divdf3
         U __gtdf2
00000470 T __ieee754_j0
         U __ieee754_log
         U __ieee754_sqrt
000009b8 T __ieee754_y0
         U __ltdf2
         U __muldf3
         U __subdf3
         U cos
         U fabs
000000b0 r pR2
00000108 r pR3
00000058 r pR5
00000000 r pR8
000000e0 r pS2
00000138 r pS3
00000088 r pS5
00000030 r pS8
00000004 t pzero
00000220 r qR2
00000280 r qR3
000001c0 r qR5
00000160 r qR8
00000250 r qS2
000002b0 r qS3
000001f0 r qS5
00000190 r qS8
00000218 t qzero
         U sin

lib_a-e_j1.o:
         U __adddf3
         U __divdf3
         U __gtdf2
00000470 T __ieee754_j1
         U __ieee754_log
         U __ieee754_sqrt
00000950 T __ieee754_y1
         U __muldf3
         U __subdf3
         U cos
         U fabs
00000004 t pone
000000b0 r pr2
00000108 r pr3
00000058 r pr5
00000000 r pr8
000000e0 r ps2
00000138 r ps3
00000088 r ps5
00000030 r ps8
00000218 t qone
00000220 r qr2
00000280 r qr3
000001c0 r qr5
00000160 r qr8
00000250 r qs2
000002b0 r qs3
000001f0 r qs5
00000190 r qs8
         U sin

lib_a-e_jn.o:
         U __adddf3
         U __divdf3
         U __floatsidf
         U __gedf2
         U __gtdf2
         U __ieee754_j0
         U __ieee754_j1
00000434 T __ieee754_jn
         U __ieee754_log
         U __ieee754_sqrt
         U __ieee754_y0
         U __ieee754_y1
00000000 T __ieee754_yn
         U __ltdf2
         U __muldf3
         U __subdf3
         U cos
         U fabs
         U sin


lib_a-e_sinh.o:
         U __adddf3
         U __divdf3
         U __gtdf2
         U __ieee754_exp
00000000 T __ieee754_sinh
         U __muldf3
         U __subdf3
         U expm1
         U fabs


lib_a-ef_asin.o:
         U __addsf3
         U __divsf3
         U __gtsf2
00000000 T __ieee754_asinf
         U __ieee754_sqrtf
         U __mulsf3
         U __subsf3
         U fabsf


lib_a-ef_j0.o:
         U __addsf3
         U __divsf3
         U __gtsf2
0000035c T __ieee754_j0f
         U __ieee754_logf
         U __ieee754_sqrtf
000006cc T __ieee754_y0f
         U __ltsf2
         U __mulsf3
         U __subsf3
         U cosf
         U fabsf
00000058 r pR2
00000084 r pR3
0000002c r pR5
00000000 r pR8
00000070 r pS2
0000009c r pS3
00000044 r pS5
00000018 r pS8
00000004 t pzerof
00000110 r qR2
00000140 r qR3
000000e0 r qR5
000000b0 r qR8
00000128 r qS2
00000158 r qS3
000000f8 r qS5
000000c8 r qS8
000001a0 t qzerof
         U sinf

lib_a-ef_j1.o:
         U __addsf3
         U __divsf3
         U __gtsf2
0000031c T __ieee754_j1f
         U __ieee754_logf
         U __ieee754_sqrtf
0000062c T __ieee754_y1f
         U __mulsf3
         U __subsf3
         U cosf
         U fabsf
00000004 t ponef
00000058 r pr2
00000084 r pr3
0000002c r pr5
00000000 r pr8
00000070 r ps2
0000009c r ps3
00000044 r ps5
00000018 r ps8
000001a0 t qonef
000000b0 r qr2
000000e0 r qr8
000000c8 r qs2
000000f8 r qs8
         U sinf

lib_a-ef_sinh.o:
         U __addsf3
         U __divsf3
         U __gtsf2
         U __ieee754_expf
00000000 T __ieee754_sinhf
         U __mulsf3
         U __subsf3
         U expm1f
         U fabsf

lib_a-er_lgamma.o:
         U __adddf3
         U __divdf3
         U __eqdf2
         U __fixdfsi
         U __floatsidf
00000004 T __ieee754_lgamma_r
         U __ieee754_log
         U __kernel_cos
         U __kernel_sin
         U __ltdf2
         U __muldf3
         U __nedf2
         U __subdf3
         U fabs
         U floor


lib_a-erf_lgamma.o:
         U __addsf3
         U __divsf3
         U __eqsf2
         U __fixsfsi
         U __floatsisf
00000004 T __ieee754_lgammaf_r
         U __ieee754_logf
         U __kernel_cosf
         U __kernel_sinf
         U __ltsf2
         U __mulsf3
         U __nesf2
         U __subsf3
         U fabsf
         U floorf

lib_a-k_sin.o:
         U __adddf3
         U __fixdfsi
00000000 T __kernel_sin
         U __muldf3
         U __subdf3

lib_a-kf_sin.o:
         U __addsf3
         U __fixsfsi
00000000 T __kernel_sinf
         U __mulsf3
         U __subsf3

lib_a-s_asinh.o:
         U __adddf3
         U __divdf3
         U __gtdf2
         U __ieee754_log
         U __ieee754_sqrt
         U __muldf3
00000000 T asinh
         U fabs
         U log1p

lib_a-s_cos.o:
         U __ieee754_rem_pio2
         U __kernel_cos
         U __kernel_sin
         U __subdf3
00000000 T cos

lib_a-s_isinf.o:
00000000 T isinf

lib_a-s_isinfd.o:
00000000 T __isinfd

lib_a-s_sin.o:
         U __ieee754_rem_pio2
         U __kernel_cos
         U __kernel_sin
         U __subdf3
00000000 T sin

lib_a-sf_asinh.o:
         U __addsf3
         U __divsf3
         U __gtsf2
         U __ieee754_logf
         U __ieee754_sqrtf
         U __mulsf3
00000000 T asinhf
         U fabsf
         U log1pf

lib_a-sf_cos.o:
         U __ieee754_rem_pio2f
         U __kernel_cosf
         U __kernel_sinf
         U __subsf3
00000000 T cosf

lib_a-sf_isinf.o:
00000000 T isinff

lib_a-sf_isinff.o:
00000000 T __isinff

lib_a-sf_sin.o:
         U __ieee754_rem_pio2f
         U __kernel_cosf
         U __kernel_sinf
         U __subsf3
00000000 T sinf

lib_a-w_asin.o:
         U __errno
         U __fdlib_version
         U __gtdf2
         U __ieee754_asin
         U __isnand
00000004 T asin
         U fabs
         U matherr
         U nan

lib_a-w_sincos.o:
         U cos
         U sin
00000000 T sincos

lib_a-w_sinh.o:
         U __errno
         U __fdlib_version
         U __gtdf2
         U __ieee754_sinh
         U finite
         U matherr
00000004 T sinh

lib_a-wf_asin.o:
         U __errno
         U __extendsfdf2
         U __fdlib_version
         U __gtsf2
         U __ieee754_asinf
         U __truncdfsf2
00000004 T asinf
         U fabsf
         U isnanf
         U matherr
         U nan

lib_a-wf_sincos.o:
         U cosf
00000000 T sincosf
         U sinf

lib_a-wf_sinh.o:
         U __errno
         U __extendsfdf2
         U __fdlib_version
         U __gtsf2
         U __ieee754_sinhf
         U __truncdfsf2
         U finitef
         U matherr
00000004 T sinhf

EDIT1: Я протестировал еще несколько, и проблема заключается в следующем (не то, что я изначально указал выше):

double aa;
double bb = 1.0;
double cc;
aa = sin(1.0);
cc = sin (bb);

Что происходит, когда я пытаюсь построить, так это то, что я получаю 'неопределенная ссылка' в последней строке, что означает, что когда я использую константы, все в порядке, но когда я передаю переменные функциям sin, это не будет ссылка на сайт. Я также протестировал многие другие математические функции, и у меня точно такая же проблема с компоновщиком. Как только я передаю переменную математической функции, я больше не могу связываться. Любые идеи?


person theAlse    schedule 30.06.2011    source источник
comment
оба вызова функций находятся в одном файле?   -  person Heisenbug    schedule 30.06.2011
comment
Если вы используете инструмент вашей платформы для отображения таблицы символов для объектного файла (например, nm ), перечислены ли отсутствующие функции в libm.a? Ошибка указывает на то, что проблема находится на этапе компоновки, после чего заголовочные файлы больше не используются. Другими словами, содержимое math.h не повлияет на проблему.   -  person outis    schedule 30.06.2011
comment
да, pow и asin идут сразу друг за другом (я пропустил объявление переменной выше)   -  person theAlse    schedule 30.06.2011
comment
@Alborz Возможно, сделать nm libm.a?   -  person cnicutar    schedule 30.06.2011
comment
@cnicutar @outis, что я должен искать в выводе nm? Я вижу такие вещи, как: lib_a-ef_asin.o: и lib_a-e_asin.o: и lib_a-e_sinh.o:   -  person theAlse    schedule 30.06.2011
comment
@Alborz: как указывалось ранее, вы ищете недостающие функции, перечисленные в выводе (вероятно, с префиксом _).   -  person outis    schedule 30.06.2011
comment
pow может быть реализован вашим компилятором как встроенный.   -  person interjay    schedule 30.06.2011
comment
Проверьте свой LD_LIBRARY_PATH. Возможно, вы ищете библиотеку, отличную от той, которую использует компоновщик. Помните, что заголовочный файл math.h также может ссылаться на другую библиотеку, отличную от выбранной.   -  person cdarke    schedule 30.06.2011
comment
Можете ли вы воспроизвести проблему только с одним исходным файлом, собрав исполняемый файл без каких-либо make-файлов, например: gcc -o test test.c -lm или, возможно, gcc -static -o test test.c -lm?   -  person n. 1.8e9-where's-my-share m.    schedule 30.06.2011
comment
попробуйте добавить -std=c99 в строку компиляции, чтобы посмотреть, что произойдет   -  person Vinicius Kamakura    schedule 30.06.2011
comment
Вас интересуют только символы с внешней связью, режим nm следует использовать выборочно: nm --extern-only libm.a   -  person Clifford    schedule 01.07.2011
comment
@hexa: это изменит поведение компилятора, а не содержимое библиотеки. Выбор диалекта может удалить части заголовочного файла, но это вызовет ошибку компилятора, а не компоновщика.   -  person Clifford    schedule 01.07.2011
comment
Если вы оптимизируете компиляцию, компилятор может оптимизировать вызов sin(1.0) во время выполнения, заменив его константой, вычисляемой во время компиляции. Включили ли вы #include ‹math.h› (см. ответ Джонатана)?   -  person David Hammen    schedule 01.07.2011
comment
На какой платформе вы находитесь? Какой компилятор C вы используете? Вы кросс-компилируете? Какая командная строка выполняется для связывания? (Я вижу DOS/Windows C: пути и архитектуру PowerPC.) Есть ли шанс, что вы используете ‹tgmath.h› для типовой математики?   -  person Jonathan Leffler    schedule 01.07.2011


Ответы (4)


Компоновщик не жалуется на pow((double) 2, (double) 3), потому что компилятор заменяет его константой 8.0. Вы не должны зависеть от этого поведения; вместо этого вы всегда должны правильно использовать параметр -lm. (Кстати, это более четко записывается как pow(2.0, 3.0).

Рассмотрим следующую программу:

#include <stdio.h>
#include <math.h>
int main(void) {
    double x = 0.1;
    printf("%g\n", pow(2.0, 3.0));
    printf("%g\n", asin(x));
    return 0;
}

Когда я компилирую и связываю его в своей системе, используя

gcc c.c -o c

Я получил:

/tmp/ccXx8ZRL.o: In function `main':
c.c:(.text+0x36): undefined reference to `asin'
collect2: ld returned 1 exit status

Обратите внимание, что он жалуется на asin, но не на pow.

Если я изменю вызов pow на pow(x, 3.0), я получу:

/tmp/ccOeSaBK.o: In function `main':
c.c:(.text+0x24): undefined reference to `pow'
c.c:(.text+0x52): undefined reference to `asin'
collect2: ld returned 1 exit status

Обычно, если вы хотите вызвать стандартную функцию математической библиотеки, вам нужно иметь #include <math.h> в начале исходного файла (я полагаю, что он у вас уже есть) и вам нужно передать параметр -lm компилятору после файла, которому это нужно. (Компоновщик отслеживает ссылки, которые еще не были разрешены, поэтому ему нужно сначала увидеть объектный файл, который ссылается на asin, чтобы он мог разрешить его, когда увидит математическую библиотеку.)

Компоновщик не жалуется на вызов pow(2.0, 3.0), потому что gcc достаточно умен, чтобы преобразовать его в константу 8.0. В скомпилированном объектном файле нет вызова функции pow, поэтому компоновщику не нужно его разрешать. Если я изменю pow(2.0, 3.0) на pow(x, 3.0), компилятор не будет знать, каким будет результат, поэтому он генерирует вызов.

person Keith Thompson    schedule 10.07.2015

Последовательность для -lm -lc -lgcc играет очень важную роль. У меня работает только эта последовательность.

Эти команды идут в опции компоновщика!

person ottelo    schedule 27.09.2012
comment
Опции -lc и lgcc обычно не нужны. Какая среда требует их? - person Keith Thompson; 26.03.2016

Вы включаете <math.h> везде?

Обратите внимание, что имена в библиотеке имеют префикс __ieee754_, а имена, которые компоновщик не может найти, — нет.

Что происходит, когда вы компилируете этот код?

#include <math.h>

int main(void)
{
    double d = pow(2, 3);
    double e = asin(1.0 / d);
    return (int)(e+1);
}

Если файл mathtest.c, скомпилируйте с помощью:

gcc -o mathtest mathtest.c -lm

(Учитывая, что это не скомпилируется, какие символы определены в mathtest.o?)


Я добавил комментарий к основному вопросу:

На какой платформе вы находитесь? Какой компилятор C вы используете? Вы кросс-компилируете? Какая командная строка выполняется для связывания? (Я вижу DOS/Windows C: пути и архитектуру PowerPC.) Есть ли шанс, что вы используете математику, основанную на типах?

Глядя на пути LOAD, которые вы указываете, я вижу:

LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/bin/../lib/gcc/powerpc-eabi/4.3.3/../../../../powerpc-eabi/lib/nof\libm.a

Что, я думаю, можно упростить до:

LOAD c:/gnu/powerpc-eabi/3pp.ronetix.powerpc-eabi/powerpc-eabi/lib/nof\libm.a

Одна часть этого пути, которая меня интригует, — это часть nof; может ли это быть «без плавающей запятой»? Другая часть, которая меня действительно заинтриговала, — это наличие powerpc с префиксом c:; это попахивает кросс-компиляцией для PowerPC на платформе Windows. Важно быть откровенным и недвусмысленным в таких вещах; нам нужна такая информация, чтобы иметь возможность помочь вам разумно.

Это была библиотека libm.a, которую вы тестировали, или вы экспериментировали с другим файлом?

person Jonathan Leffler    schedule 30.06.2011
comment
Неопределенная ссылка - это ошибка компоновщика, а не ошибка компилятора, отсутствие включения файла заголовка приведет к ошибке компилятора (или предупреждению в C89). - person Clifford; 01.07.2011
comment
@Clifford: если только заголовок не сопоставил имя исходного кода с asin на __ieee574_asin. Вывод из nm показывает символ __ieee574_asin, и если заголовок отображает имя, как предложено, то вызов функции без заголовка будет означать, что была вызвана «неправильная» функция. Если образец кода, который я предоставил, содержит ссылки, а исходный код плаката — нет, я был бы склонен считать это «доказанным случаем». Да, вы можете с полным основанием утверждать, что вы должны иметь возможность написать extern double asin(double);, и это должно работать, но я уже видел такое сопоставление имен. - person Jonathan Leffler; 01.07.2011
comment
ISO/IEC 9899:1999 (E) §7.1.4/2: Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header. Таким образом, если требуется включение, реализация не соответствует требованиям. - person bdonlan; 01.07.2011
comment
@bdonlan: я никогда не говорил иначе - и я знаю об этом стандарте. Но я уже видел подобные игры на (Linux) реализациях. И это одна (основная) причина, по которой лучше включить системный заголовок, чем сомневаться в системе. Но я думаю, что если мой пример не компилируется чисто, то реализация просто сломана. Если он компилируется чисто, а код OP - нет, то код OP делает что-то равносильное тому, что не включает <math.h> там, где этого требует реализация... и исправление включения <math.h> будет работать везде. - person Jonathan Leffler; 01.07.2011
comment
@ Джонатан, вы написали (почти) тот же код, что и я изначально, и вы связываетесь с -lm, как и я. Я не вижу никакой разницы. Я снова получил неопределенную ссылку на «асин». - person theAlse; 01.07.2011
comment
@alborz: ОК - если код, который я показал, не связан, вам нужно исправить свой компилятор, ваши заголовки или ваши библиотеки. Текущая установка нарушена. Чего я не могу сказать, так это того, что проблема в ваших заголовках или в ваших библиотеках, или у вас есть что-то очень странное, установленное в вашем /etc/ld.so.conf или эквивалентном (поэтому он использует неправильную математическую библиотеку) . Кроме того, обычно я ожидаю, что будет libm.so, а не libm.a; Я не знаю, является ли это фактором. И, наконец (пока), проверили ли вы какие-либо другие недостающие символы из стандартного набора? - person Jonathan Leffler; 01.07.2011
comment
@Jonathan: я думаю, что нашел здесь настоящую проблему. пожалуйста, смотрите отредактированный пост выше - person theAlse; 01.07.2011
comment
@Alborz: становится все страньше и страньше. Поскольку вы не показали нам связанный пример, который воспроизводит проблему, я больше не могу вам помочь. - person Jonathan Leffler; 01.07.2011

Вы можете использовать "filename.c -lm" для решения этой проблемы. И, пожалуйста, не забудьте использовать заголовочный файл math.h

person Mayank Kashyap    schedule 27.09.2016