Compilando o LLVM como uma biblioteca no Mac OS X 10.6

January 15th, 2011 § 0 comments § permalink

Esses dias andei brincando um pouco com o projeto ruby-llvm, cujo propósito é criar bindings em Ruby para o LLVM usando o Ruby-FFI. Para aprender sobre o projeto, adicionei alguns testes para a funcionalidade já existente e corrigi alguns pequenos problemas.

Para fazer isso, eu precisei compilar a biblioteca compartilhada do LLVM, que na maioria das plataformas é algo trivial. De fato, normalmente só é necessário especificar o flag abaixo no script de configuração:

./configure --enabled-shared

Eu uso o brew, na verdade, mas o princípio é o mesmo:

brew install llvm --shared

Entretanto, a compilação acima, embora passe limpa no Mac OS X, resulta nos seguintes erros quando a biblioteca é carregada no Ruby-FFI:

dyld: loaded: /Users/<user>/llvm/2.8/lib/libLLVM-2.8.dylib
dyld: lazy symbol binding failed: Symbol not found: 
    __ZN4llvm2cl6Option11addArgumentEv
  Referenced from: /Users/<user>/llvm/2.8/lib/libLLVM-2.8.dylib
  Expected in: flat namespace

dyld: Symbol not found: __ZN4llvm2cl6Option11addArgumentEv
  Referenced from: /Users/<user>/llvm/2.8/lib/libLLVM-2.8.dylib
  Expected in: flat namespace

Trace/BPT trap

Depois de algumas investigações e uma troca de e-mails com Takanori Ishikawa, eu cheguei ao seguinte patch que resolve o problema e permite que o LLVM seja compilado limpa e corretamente como uma biblioteca compartilhada:

diff --git a/Makefile.rules b/Makefile.rules
index 9cff105..44d5b2d 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -497,7 +497,7 @@ ifeq ($(HOST_OS),Darwin)
   # Get "4" out of 10.4 for later pieces in the makefile.
   DARWIN_MAJVERS := $(shell echo $(DARWIN_VERSION)| sed -E
's/10.([0-9]).*/\1/')

-  SharedLinkOptions=-Wl,-flat_namespace -Wl,-undefined,suppress \
+  SharedLinkOptions=-Wl,-undefined,dynamic_lookup \
                     -dynamiclib
   ifneq ($(ARCH),ARM)
     SharedLinkOptions += -mmacosx-version-min=$(DARWIN_VERSION)

As opções acima mudam os namespaces para o padrão de dois níveis do OS X e a resolução de nomes para acontecer em tempo de execução.

Usar essas opções não parecer ter causado qualquer problema em outras partes do LLVM mas eu estou curioso para entender porque não são usadas por padrão pelo projeto, especialmente considerando que muitos outros projetos fazem justamente isso como descobri depois. De fato, as opções anteriores parecem ser um legado dos dias pré-10.3 do Mac OS X. De qualquer forma, fiz essa pergunta na lista LLVM-dev.

Enquanto isso, o patch funciona para mim. Também disponibilizei uma versão modificada para o brew. YMMV.

Where Am I?

You are currently browsing the LLVM category at Superfície Reflexiva.