gcc связывает иначе, чем g++

Я преобразовал код C++ в C, и теперь я также пытаюсь изменить Makefile. У меня было это:

g++ -fPIC -o bin/linux/release/gpu_md5 cuda_md5.c cuda_md5_cpu.c obj/release/cuda_md5_gpu.cu.o 
-L/usr/local/cuda/lib64 -L../../lib64 
-L../../common/lib64/linux -L/opt/cuda/NVIDIA_CUDA_SDK/lib64 -lcudart     
-L/usr/local/cuda/lib64 -L../../lib64 
-L../../common/lib64/linux -L/opt/cuda/NVIDIA_CUDA_SDK/lib64

Насколько я знаю, я мог бы просто изменить g++ на gcc, и он должен работать хорошо, но это не так. Похоже, gcc не может найти функции из cuda_md5_cpu.c, которые я вызываю в cuda_md5.c (PS: я не включаю cuda_md5_cpu.c в cuda_md5.c):

/tmp/ccKdDJiq.o: In function `cuda_compute_md5s':
cuda_md5.c:(.text+0x201): undefined reference to `init_constants'
cuda_md5.c:(.text+0x2e2): undefined reference to `execute_kernel'
collect2: ld returned 1 exit status

Что не так? Я только что перешел с g++ на gcc.


person Frederico Schardong    schedule 14.10.2012    source источник


Ответы (1)


Я бы сказал, что есть очень хороший шанс, что obj/release/cuda_md5_gpu.cu.o (который вы, похоже, не перекомпилируете) был скомпилирован с помощью компилятора C++ и, следовательно, имеет имена символов, которые были изменены путем искажения имен.

Изменение имени — это метод, используемый компиляторами C++, позволяющий различным функциям иметь одно и то же имя, но с разными типами параметров (перегрузка), и компиляторам C не нужно делать это, поскольку перегрузка не разрешена.

Другими словами, вы можете обнаружить, что init_constants(int,float); может быть просто преобразовано компилятором C в _init_constants, но если вы используете компилятор C++, вы получите что-то вроде _init_constants_$$_IntFloat, чтобы отличить его от init_constants(int,double) или init_constants(void).

Таким образом, компоновщик, который пытается скомпилировать cuda_md5.c, скомпилированный на C, с obj/release/cuda_md5_gpu.cu.o, скомпилированный на C++, не сможет сопоставить имена функций вместе.

Вот почему вы часто видите extern "C" { ... } в коде C++, он использует правила C для экспорта имен функций (и других вещей) в компоновщик, чтобы разрешить связывание кода C и C++ вместе.

person paxdiablo    schedule 14.10.2012
comment
Я почти уверен, что больше не использую g++, вот makefile pastebin.com/Abnh7Vm2 - person Frederico Schardong; 14.10.2012
comment
@FredericoSchardong, я уверен, что нет. Но проблема в том, что CUFILES не компилируются с make-файлом, они добавляются в список OBJS, что означает, что они уже скомпилированы. Если они были скомпилированы компилятором C++ (без extern C), у вас возникнет эта проблема. - person paxdiablo; 14.10.2012
comment
@FredericoSchardong, ты должен сказать нам об этом. Вы видите его компиляцию в выходных данных Makefile? Это будет сделано только (на основе строки 344), если зависимости новее, чем объектный файл. В противном случае объектный файл останется как есть. Вы также должны быть в состоянии сказать, используя nm или аналогичный инструмент для просмотра символов в этом объектном файле. - person paxdiablo; 14.10.2012
comment
Я удаляю все *.o перед компиляцией, также я вижу создание cuda_md5_gpu.cu.o. Извините за невежество, что такое nm? - person Frederico Schardong; 14.10.2012
comment
@FredericoSchardong, nm — это инструмент UNIX, который показывает символы в объектном файле. - person paxdiablo; 14.10.2012
comment
вот вывод nm для исполняемого файла, скомпилированного с помощью g++ pastebin.com/qbFHzgik, это то, что вы имели в виду? - person Frederico Schardong; 14.10.2012
comment
@FredericoSchardong, если это ваш настоящий объектный файл, то он определенно C++. Во-первых, в строке заголовка указано #nm of the executable compiled with g++, а функция execute_kernel — _Z14execute_kerneliiiiiPjS_ (все эти i символа означают int аргумента), поэтому искажение определенно происходит. - person paxdiablo; 14.10.2012
comment
как я уже сказал, это результат того, что когда я компилирую исходный код с помощью g++, я не могу дать вам результат nm, компилируемый с помощью gcc, потому что я не могу его скомпилировать. :) - person Frederico Schardong; 14.10.2012
comment
и я написал, что #nm исполняемого файла, скомпилированного с помощью g++ - person Frederico Schardong; 14.10.2012
comment
это может помочь. - person Frederico Schardong; 14.10.2012
comment
@FredericoSchardong, это все еще C ++, о чем свидетельствует материал iiiiii. Следовательно, эта библиотека компилируется компилятором C++, поэтому мой ответ правильный. Вам нужно выяснить, как скомпилировать это с помощью компилятора C. Я не могу помочь вам с этим, так как я не использую CUDA, поэтому вам нужно будет просмотреть все документы, которые у вас есть, чтобы узнать, как это делается. - person paxdiablo; 14.10.2012
comment
похоже, что nvcc (компилятор cuda) использует gcc с языком, установленным на c++. stackoverflow.com/ вопросы/8317510/ - person Frederico Schardong; 14.10.2012
comment
проблема решена, я добавил extern C к функциям, на которые жаловался компоновщик, и все заработало! Спасибо за помощь! - person Frederico Schardong; 14.10.2012