A mesma fonte, tudo isso, só quer uma versão estática e compartilhada. Fácil de fazer?
Sim, é moderadamente fácil. Basta usar dois comandos "add_library":
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
Mesmo se você tiver muitos arquivos de origem, você colocaria a lista de fontes em uma variável cmake, por isso ainda é fácil.
No Windows, você provavelmente deve atribuir um nome diferente a cada biblioteca, pois existe um arquivo ".lib" para compartilhado e estático. Mas no Linux e Mac, você pode até dar o mesmo nome às duas bibliotecas (por exemplo, libMyLib.a
e libMyLib.so
):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
Mas não recomendo atribuir o mesmo nome às versões estática e dinâmica da biblioteca. Prefiro usar nomes diferentes, porque isso facilita a escolha da ligação estática versus dinâmica na linha de compilação para as ferramentas vinculadas à biblioteca. Normalmente eu escolho nomes como libMyLib.so
(compartilhado) e libMyLib_static.a
(estático). (Esses seriam os nomes no linux.)
-fPIC
), o que adiciona uma pequena quantidade de sobrecarga de tempo de execução quando essas bibliotecas estáticas são usadas. Portanto, para obter o máximo desempenho, essa resposta ainda é a melhor.Desde o CMake versão 2.8.8, você pode usar "bibliotecas de objetos" para evitar a compilação duplicada dos arquivos de objetos . Usando o exemplo de Christopher Bruns de uma biblioteca com dois arquivos de origem:
Dos documentos do CMake :
Simplificando, o
add_library(objlib OBJECT ${libsrc})
comando instrui o CMake a compilar os arquivos de origem em arquivos de*.o
objetos. Essa coleção de*.o
arquivos é referida$<TARGET_OBJECT:objlib>
nos doisadd_library(...)
comandos que chamam os comandos de criação de biblioteca apropriados que constroem as bibliotecas compartilhadas e estáticas a partir do mesmo conjunto de arquivos de objetos. Se você possui muitos arquivos de origem, a compilação dos*.o
arquivos pode demorar bastante; com bibliotecas de objetos, você as compila apenas uma vez.O preço que você paga é que os arquivos de objeto devem ser criados como código independente da posição, porque as bibliotecas compartilhadas precisam disso (bibliotecas estáticas não se importam). Observe que o código independente da posição pode ser menos eficiente; portanto, se você busca o desempenho máximo, deve procurar bibliotecas estáticas. Além disso, é mais fácil distribuir executáveis vinculados estaticamente.
fonte
target_link_libraries()
chamadas subseqüentes que dependem da sua biblioteca e não podem usar a "biblioteca de objetos" para vincular; esses devem ter como alvo as novas bibliotecas compartilhadas ou estáticas (e podem ser duplicadas). Mas, ao contrário da experiência dos primeiros comentaristas, isso foi bastante útil e me permitiu remover todos os alvos duplicados e cortar todos os meusCMakeLists.txt
arquivos pela metade.set_property
único funcionou quando eu useiobjlib
e não ao usar${objlib}
. Talvez essa resposta possa ser corrigida?Geralmente, não há necessidade de duplicar
ADD_LIBRARY
chamadas para seu propósito. Basta fazer uso dedurante a construção, primeiro (em um diretório fora da fonte) com
-DBUILD_SHARED_LIBS:BOOL=ON
e comOFF
no outro.fonte
É possível empacotar tudo no mesmo fôlego de compilação, como sugerido nas respostas anteriores, mas eu aconselho isso, porque no final é um hack que funciona apenas para projetos simples. Por exemplo, em algum momento você pode precisar de sinalizadores diferentes para diferentes versões da biblioteca (especialmente no Windows, onde os sinalizadores são normalmente usados para alternar entre exportar símbolos ou não). Ou, como mencionado acima, você pode colocar
.lib
arquivos em diretórios diferentes, dependendo de corresponderem a bibliotecas estáticas ou compartilhadas. Cada um desses obstáculos exigirá um novo hack.Pode ser óbvio, mas uma alternativa que não foi mencionada anteriormente é tornar o tipo da biblioteca um parâmetro:
Ter versões compartilhadas e estáticas da biblioteca em duas árvores binárias diferentes facilita o manuseio de diferentes opções de compilação. Não vejo nenhuma desvantagem séria em manter as árvores de compilação distintas, especialmente se suas compilações são automatizadas.
Observe que, mesmo que você pretenda mutualizar compilações usando uma
OBJECT
biblioteca intermediária (com as advertências mencionadas acima, portanto, você precisa de um motivo convincente para fazê-lo), ainda assim as bibliotecas finais poderão ser colocadas em dois projetos diferentes.fonte
É de fato possível. Como @Christopher Bruns disse em sua resposta, você precisa adicionar duas versões da biblioteca:
Então, conforme descrito aqui , você precisa especificar que os dois destinos devem usar o mesmo nome de saída e não substituir os arquivos um do outro:
Dessa forma, você obterá libmylib.a e libmylib.so (no Linux) ou mylib.lib e mylib.dll (no Windows).
fonte