Неопределенный символ при попытке связать с разделяемой библиотекой, созданной из объектов CUDA - PullRequest
0 голосов
/ 17 июня 2019

Я экспериментирую с созданием простого приложения из пары исходных файлов .cu и очень простой основной C ++, которая вызывает функцию из одного из файлов .cu.Я делаю общую библиотеку (файл .so) из скомпилированных файлов .cu.Я обнаружил, что все собирается без проблем, но когда я пытаюсь запустить приложение, я получаю ошибку неопределенного символа компоновщика с искаженным именем функции .cu, которую я вызываю из main ().Если вместо этого я создаю статическую библиотеку, мое приложение работает нормально.Вот созданный мной make-файл:

.PHONY: clean
NVCCFLAGS = -std=c++11 --compiler-options '-fPIC'
CXXFLAGS = -std=c++11
HLIB = libhello.a
SHLIB = libhello.so
CUDA_OBJECTS = bridge.o add.o

all: driver

%.o :: %.cu
    nvcc -o $@ $(NVCCFLAGS) -c -I. $<

%.o :: %.cpp
    c++ $(CXXFLAGS) -o $@ -c -I. $<

$(HLIB): $(CUDA_OBJECTS)
    ar rcs $@ $^

$(SHLIB): $(CUDA_OBJECTS)
    nvcc $(NVCCFLAGS) --shared  -o $@ $^

#driver : driver.o $(HLIB)
#   c++ -std=c++11 -fPIC -o $@ driver.o -L. -lhello -L/usr/local/cuda-10.1/targets/x86_64-linux/lib -lcudart

driver : driver.o $(SHLIB)
    c++ -std=c++11 -fPIC -o $@ driver.o -L. -lhello

clean:
    -rm -f driver *.o *.so *.a

Вот различные исходные файлы, которые make-файл принимает в качестве фуража.add.cu:

__global__ void add(int n, int* a, int* b, int* c) {
    int index = threadIdx.x;
    int stride = blockDim.x;

    for (int ii = index; ii < n; ii += stride) {
        c[ii] = a[ii] + b[ii];
    }
}

add.h:

extern __global__ void add(int n, int* a, int* b, int* c);

bridge.cu:

#include <iostream>
#include "add.h"

void bridge() {
    int N = 1 << 16;
    int blockSize = 256;
    int numBlocks = (N + blockSize - 1)/blockSize;

    int* a;
    int* b;
    int* c;

    cudaMallocManaged(&a, N*sizeof(int));
    cudaMallocManaged(&b, N*sizeof(int));
    cudaMallocManaged(&c, N*sizeof(int));

    for (int ii = 0; ii < N; ii++) {
        a[ii] = ii;
        b[ii] = 2*ii;
    }

    add<<<numBlocks, blockSize>>>(N, a, b, c);

    cudaDeviceSynchronize();

    for (int ii = 0; ii < N; ii++) {
        std::cout << a[ii] << " + " << b[ii] << " = " << c[ii] << std::endl;
    }

    cudaFree(a);
    cudaFree(b);
    cudaFree(c);
}

bridge.h:

extern void bridge();

driver.cpp:

#include "bridge.h"

int main() {
    bridge();
    return 0;
}

Я очень новичок в cuda, поэтому я ожидаю, что именно здесь я делаю что-то не так.Я немного поиграл с использованием объявлений extern "C", но это, кажется, просто перемещает ошибку "undefined symbol" со времени выполнения на время сборки.

Я знаком с различными способами, которыми можно завершитьс неопределенным символом, и я упомянул различные эксперименты, которые я уже провел (статическое связывание, объявления extern "C"), которые заставляют меня думать, что эта проблема не решается предложенным дублирующим вопросом.

Мой неразрешенный символ - _Z6bridgev

Мне кажется, что компоновщик должен иметь возможность разрешить символ.Если я могу использовать nm на driver.o, я вижу:

0000000000000000 T main
                 U _Z6bridgev

И если я запускаю nm на libhello.so, я вижу:

0000000000006e56 T _Z6bridgev

1 Ответ

0 голосов
/ 18 июня 2019

Когда Роберт Кровелла смог заставить мой пример работать на своей машине, а я не смог заставить его пример работать на своем, я начал понимать, что моя проблема не имеет ничего общего с cuda или nvcc. Это был тот факт, что с общей библиотекой загрузчик должен разрешать символы во время выполнения, а моя общая библиотека не находилась в «известном месте». Я только что создал простой тестовый пример исключительно с исходниками на С ++ и повторил свой сбой. После того как я скопировал libhello.so в /usr/local/lib, я смог успешно запустить driver. Итак, я в порядке с закрытием моего первоначального вопроса, если это воля людей.

...