Compreendendo a implicação LGPL em #include

Sep 24 2020

Eu perguntei sobre a vinculação dinâmica em C ++ em stackoverflow (https://stackoverflow.com/q/64039902/14321464), no entanto, fiquei intrigado com as respostas sobre meu desejo de manter meu código-fonte descoberto pelo copyleft LGPL. Eu também tenho me perguntado isso e pesquisado sobre isso há dias aqui no stackexchange, lendo muitos esclarecimentos feitos por várias equipes (como do Teems:http://teem.sourceforge.net/lgpl.html) e pesquisando no Google. Isso é o que eu entendi até agora:

  1. Se eu escrever e compilar meu código-fonte e vincular a biblioteca LGPL estaticamente (via .a no Linux ou .lib no Windows (... talvez? Não tenho certeza de qual é o equivalente a um arquivo .a no Windows)), estou vinculado a pelo menos fornecer o arquivo de saída (.o) da compilação do meu código-fonte para que as pessoas possam usar seu vinculador de escolha para vincular novamente e compilar o arquivo .o no executável final usando a biblioteca de sua escolha.

  2. Se eu escrever e compilar seu código-fonte e vincular a biblioteca LGPL dinamicamente (via .so no Linux ou .dll no Windows), e se decidir redistribuir o arquivo .SO como parte da distribuição do meu software, devo fornecer a fonte código da biblioteca LGPL que está em uso e distribuída (suponho que, apenas por hospedagem própria, posso até estar inclinado a apenas empacotar o código-fonte como parte da distribuição).

  3. Se eu escrever e compilar meu código-fonte e vincular a biblioteca LGPL dinamicamente (via .so no Linux, ou .dll no Windows), e apenas declarar que para executar este programa os usuários devem adquirir as bibliotecas LGPL, então nenhum código-fonte precisa ser fornecido ao usuário final. Eu só preciso dizer como e onde esses arquivos precisam ser colocados para que o programa possa ser executado.

E depois de ler o LGPL v2.1 e LGPL v3 de um lado para outro, ainda tenho 2 perguntas em minha cabeça:

  1. Considere este caso: uma biblioteca LGPL v2.1 fornece um conjunto de arquivos .so / .dll, bem como uma pasta de inclusão contendo todos os arquivos .h (cabeçalho) relacionados a .so / .dll (descrevendo todas as estruturas, classes, construtores e destruidores, e todas as declarações de função no .so / .dll compilado).

Tanto quanto eu entendo, a vinculação dinâmica significa que o programa deve ser capaz de ser executado (seja via terminal usando ./(nome executável), clicando duas vezes no executável ou alguma outra forma de execução do executável conforme pretendido pelo host. System) e ainda capaz de funcionar mesmo sem o .so / .dll presente (exibindo uma tela de erro ou apenas forçando o fechamento).

Então, nesse caso, considere este exemplo:

sampleso.hpp

#IFNDEF SAMPLESO_HPP__
#DEFINE SAMPLESO_HPP__

struct carDesc
{
    const char *model;
    int prod_year;
    int wheel_num;
    const char *license_plate;
    const char *colour;
} car;

carDesc fillCarID(void);

sampleso.cpp

#include "sampleso.hpp"

carDesc fillCarID(void)
{
    car.name = "Ford Fiesta";
    car.prod_year = 2014;
    car.wheel_num = 4;
    car.license_plate = "D 1234 ABC";
    car.colour = "Midnight blue";
    
    return car;
}

e esses 2 são compilados para se tornarem libsampleso.so (g ++ sampleso.cpp -fPIC -shared -Wall -ldl -o libsampleso.so). Em seguida, distribuo esse código como LGPL v2.1 com libsampleso.so e sampleso.hpp. Se, mais tarde, eu usar libsampleso.so por:

main.cpp (v1)

#include <iostream>
#include "sampleso.h" //<< THIS IS THE INTERESTING BIT

int main (void)
{
     carDesc fordCar;
    
     fordCar = fillCarID(); //I know this function will produce NOTHING USEFUL, but let's just pretend it is
     ...
     return EXIT_SUCCESS;
}

e compilá-lo por ligação dinâmica (g ++ main.cpp -Wall -Wextra -std = c ++ 17 -L. -ldl -lsampleso -o main), é a adição de #include "sampleso.h"torna meu main.cpp (V1) contado como trabalhos derivados , portanto, forçando o código-fonte de main.cpp a ser divulgado como copyleft ou não? Ou devo ir mais longe e usar dlopen, dlsym e dlclose para ser considerado um link dinâmico (consulte main.cpp V2)? Até que ponto a FSF e a LGPL contam um programa como vínculo dinâmico (apenas mencionando-o como parte do parâmetro -l o suficiente? Ou eu tenho que literalmente chamar a biblioteca usando dlopen e remover todos os #include "sampleso.h"lugares em meu código para ser considerado dinâmico o suficiente? ) Todos falaram sobre .so e .dll, mas ninguém fala sobre a inclusão do arquivo de cabeçalho LGPL e a compilação de qualquer código com cabeçalho LGPL incluído.

main.cpp (v2)

#include <iostream>
#include <dlfcn.h> //Completely has no sampleso.hpp in it

int main (void)
{
     //... some dlopen codes here to find the libsampleso.so, and handle the error if it failed to be found in the aformentioned location ...

     struct carDesc * fordCar;
     fordCar = reinterpret_cast<struct carDesc*>(dlsym(hHandler,"car"));
    
     carDesc(*__fn_fillCarIDv)(void);
     __fn_fillCarIDv = reinterpret_cast<carDesc(*)(void)>(dlsym(hHandler,"_Z9fillCarIDv"));

     fordCar = __fn_fillCarIDv(); //doesn't work, error: function returns incomplete type "carDesc" C/C++(862), still working on how to make it work
     return EXIT_SUCCESS;
}
  1. Uma vez que LGPL v2.1 e v3 exige que o usuário atualize / faça downgrade da biblioteca compartilhada conforme achar necessário, enquanto mantém a capacidade de execução do executável, que tal um executável que requer uma versão de biblioteca específica (ainda com link dinâmico, mas uma versão específica do arquivo .so / .dll é obrigatório pelo programador)? Isso torna o usuário incapaz de fazer upgrade ou downgrade como achar melhor, uma vez que os usuários estão limitados a essa versão de biblioteca específica e, se eles fizerem upgrade ou downgrade, o programa também falhará.

Sinto muito se esta pergunta parece mais um ensaio, mas vindo de um país diferente dos EUA, é muito difícil interpretar claramente o que constitui a LGPL e onde estão os limites onde a LGPL se aplica ou não às aplicações.

EDITAR: Eu sei sobre todas as outras coisas legais exigidas pela licença LGPL (mencionando o uso delas na minha licença, fornecendo o texto completo da licença LGPL e hospedagem de códigos LGPL, etc.) Eu só quero me concentrar na seção 4, 5 e 6 que ainda é debatido por muitos até que ponto alguém pode dizer que algo é obra derivada.

Respostas

3 BartvanIngenSchenau Sep 24 2020 at 21:11

O LGPLv2.1 contém estes parágrafos que são diretamente relevantes para sua pergunta

Quando um "trabalho que usa a Biblioteca" usa material de um arquivo de cabeçalho que faz parte da Biblioteca, o código-objeto do trabalho pode ser um trabalho derivado da Biblioteca, mesmo que o código-fonte não seja. Se isso for verdade, é especialmente significativo se a obra puder ser vinculada sem a Biblioteca ou se a própria obra for uma biblioteca. O limite para que isso seja verdade não é precisamente definido por lei.

Se tal arquivo de objeto usar apenas parâmetros numéricos, layouts de estrutura de dados e acessadores, e pequenas macros e pequenas funções inline (dez linhas ou menos de comprimento), então o uso do arquivo de objeto é irrestrito, independentemente de ser legalmente um derivado trabalhos.

O LGPLv3 tem uma seção semelhante:

3. Código de objeto que incorpora material de arquivos de cabeçalho de biblioteca.

A forma de código-objeto de um Aplicativo pode incorporar material de um arquivo de cabeçalho que faz parte da Biblioteca. Você pode transmitir esse código-objeto nos termos de sua escolha, desde que, se o material incorporado não se limitar a parâmetros numéricos, layouts de estrutura de dados e acessores ou pequenas macros, funções embutidas e modelos (dez ou menos linhas de comprimento), você faça ambos os seguintes: [...]

Em termos que também podem ser entendidos por humanos normais, se você usar um arquivo de cabeçalho de uma biblioteca LGPL que contém apenas

  • parâmetros numéricos
  • layouts de estrutura de dados
  • acessores para essa estrutura de dados
  • pequenas macros (menos de 10 linhas cada)
  • pequenas funções inline (menos de 10 linhas cada)

então seu código não será "infectado" pelos termos da LGPL e você poderá distribuir seu código sob qualquer licença que desejar, incluindo uma licença de código fechado.

É aceito pela FSF que não há garantia de que essas partes da biblioteca possam ser substituídas pelos usuários finais.