Как игнорировать неопределенные символы во время выполнения в Linux? - PullRequest
3 голосов
/ 03 августа 2010

Я знаю, что по умолчанию неопределенные символы игнорируются во время компиляции.Однако я также хотел бы, чтобы они игнорировались во время выполнения.Мне нужно распространять .so, который будет работать с и без MPI.Я заранее буду знать, если это работа MPI, а если нет, я не буду делать вызовы MPI_ *.Если это не запуск MPI, мне нужно, чтобы приложение не заботилось о том, что оно не может разрешать символы MPI_ *.

Возможно ли это?Я мог бы поклясться, что делал это раньше, но не могу заставить его работать.При каждом запуске я сразу получаю следующее, хотя логика в моем коде никогда не позволяет ссылаться на этот символ:

undefined symbol: hpmp_comm_world

Для чего стоит использовать компилятор Intel Fortran для создания файла .so.

EDIT

Я обнаружил флаг компоновщика: "-z lazy", который должен разрешать ссылки на функции при вызове функции, и это то, что я хочу.Это не решает мою проблему, но hpmp_comm_world - это переменная, а не функция.Должно ли это иметь значение?

1 Ответ

6 голосов
/ 03 августа 2010

Вы можете определить символ как слабую ссылку на его определение. Тогда значение символа будет равно нулю, если определение отсутствует.

Например, предположим, что следующим является ref.c, который ссылается на функцию и переменную, которые могут присутствовать или не присутствовать; мы будем использовать его для сборки libref.so (соответствует вашей библиотеке, в вашем вопросе):

#include <stdio.h>

void global_func(void);
void global_func(void) __attribute__ ((weak));

extern int global_variable __attribute__((weak));

void ref_func() {
  printf("global_func = %p\n", global_func);
  if (&global_variable)
    global_variable++;
  if (global_func)
    global_func();
}

Здесь global_func и global_variable - слабые ссылки на возможно доступные функцию и переменную. Этот код печатает адрес функции, увеличивает переменную, если она присутствует, и вызывает функцию, если она присутствует. (Обратите внимание, что адреса функции и переменной равны нулю, когда они не определены, поэтому &global_variable необходимо сравнивать с нулем.)

И предположим, что это def.c, который определяет global_func и global_variable; мы будем использовать его для сборки libdef.so (соответствует MPI в вашем вопросе):

#include <stdio.h>

int global_variable;

void global_func(void) {
  printf("Hi, from global_func!  global_variable = %d\n", global_variable);
}

И, наконец, предположим, что у нас есть основная программа main.c, которая вызывает ref_func из libref.so:

#include <stdio.h>

extern void ref_func(void);

int main(int argc, char **argv) {
  printf("%s: ", argv[0]);
  ref_func();
  return 0;
}

Вот Makefile, который создает libref.so и libdef.so, а затем создает два исполняемых файла, каждый из которых ссылается на libref.so, но только один из которых ссылается на libdef.so:

all: ref-absent ref-present
ref-absent: main.o libref.so
    $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
ref-present: main.o libref.so libdef.so
    $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@

lib%.so: %.o
    $(CC) $(CFLAGS) $(LDFLAGS) -shared $^ -o $@

ref.o def.o: CFLAGS += -fpic

clean:
    rm -f *.o *.so ref-absent ref-present

Выполнить сборку:

$ make
cc    -c -o main.o main.c
cc -fpic   -c -o ref.o ref.c
cc   -shared ref.o -o libref.so
cc   main.o libref.so -o ref-absent
cc -fpic   -c -o def.o def.c
cc   -shared def.o -o libdef.so
cc   main.o libref.so libdef.so -o ref-present
$ 

Обратите внимание, что ref-отсутствующий и ref-present связаны без проблем, даже если для ref-отсутствующего нет определения global_name.

Теперь мы можем запускать программы и видеть, что ref-отсутствующий пропускает вызов функции, а ref-present использует его. (Мы должны установить LD_LIBRARY_PATH, чтобы динамический компоновщик мог находить наши общие библиотеки в текущем каталоге.)

$ LD_LIBRARY_PATH=. ./ref-absent
./ref-absent: global_func = (nil)
$ LD_LIBRARY_PATH=. ./ref-present
./ref-present: global_func = 0x15d4ac
Hi, from global_func!  global_variable = 1
$ 

Хитростью для вас будет получение атрибута ((weak)), прикрепленного к каждому объявлению каждой функции MPI, на которую ссылается ваша библиотека. Однако, как показано в ref.c, может быть несколько объявлений, и пока одно из них упоминает слабый атрибут, все готово. Так что вам, вероятно, придется сказать что-то вроде этого (я действительно не знаю MPI):

#include <mpi.h>

mpi_fake_type_t mpi_function_foo(mpi_arg_type_t) __attribute__((weak));
mpi_fake_type_t mpi_function_bar(mpi_other_arg_type_t) __attribute__((weak));

Каждая ссылка на функцию MPI должна находиться в пределах ((слабой)) декларации для этой функции; Вот как компилятор решает, какую ссылку на символ поместить в объектный файл. Вам понадобятся автоматические тесты, чтобы убедиться, что вы случайно не сгенерировали неслабые ссылки.

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