Skip to content

SDK empacotado, seletor de DLL e instalador (v0.2.0) - #3

Merged
blackfoxsoftware merged 5 commits into
devfrom
feat/sdk-2.9.9-e-empacotamento
Sep 2, 2026
Merged

SDK empacotado, seletor de DLL e instalador (v0.2.0)#3
blackfoxsoftware merged 5 commits into
devfrom
feat/sdk-2.9.9-e-empacotamento

Conversation

@blackfoxsoftware

Copy link
Copy Markdown
Owner

O que muda

O app leva a wslcsdk.dll consigo — o pacote Microsoft.WSL.Containers é MIT, então redistribuir é permitido, e LICENSE.txt e NOTICE.txt vão junto.

São duas DLLs, e a escolha é em tempo de execução, porque o SDK precisa casar com a versão do WSL. Isso foi medido nas duas direções, nesta máquina:

WSL 2.9.4 WSL 2.9.9
SDK 2.9.3 funciona WSLC_E_SDK_UPDATE_NEEDED já no WslcGetVersion
SDK 2.9.9 segfault em WslcGetSessionTerminationEvent funciona

SDK novo demais é o caso perigoso: nada no header denuncia — a declaração da função que quebra é byte a byte idêntica nas duas versões, e os 18 structs também. A regra em native/bundled.ts usa a DLL mais nova que não passe da versão do WSL.

Seletor de DLL na aba Sistema. O arquivo escolhido é sondado antes de ser aceito — carregado num binding próprio, lido (versão, ABI, SHA-256) e descarregado, sem tocar na sessão viva. Arquivo errado é recusado ali, em vez de virar um motor nativo quebrado na próxima abertura.

Detecção de ABI. A 2.9.9 mudou duas assinaturas sem mudar nada visível (WslcSessionAuthenticate ganhou tokenType; WslcInstallWithDependencies ganhou components e options), o que corromperia login em registry e instalação guiada em silêncio. O bindings.ts detecta a ABI pelo símbolo WslcOpenContainer e adapta.

Containers nativos sobrevivem ao fechamento do app na ABI 2.9.9: param e são reabertos por nome na execução seguinte. É a limitação que o ROADMAP documentava.

Instalador NSIS + portátil (x64), com as DLLs em extraResources e o koffi fora do asar. O app.asar caiu de 109 MB para 8,4 MB ao mover para devDependencies tudo o que só o renderer usa. O release empacota antes de criar a tag e roda um teste de fumaça que abre o .exe de verdade.

Ícone gerado do icon.svg.

Achados que valem revisão

  • WslcGetVersion devolve a versão do WSL instalado, não a da DLL — binários diferentes respondem o mesmo número. O campo sdkVersion virou wslVersion, e a UI dizia "SDK".
  • O registro de tipos do koffi era por nome, num namespace global, e impedia carregar uma segunda DLL. Saiu de dentro do load.
  • A licença do SDK é MIT, não "não redistribuível" como o README dizia.

Checklist

  • A PR aponta para a dev
  • npm run check passa — 310 testes
  • npm run test:e2e passa — 155 testes
  • patchnotes.json com a entrada de 0.2.0
  • version do package.json subido para 0.2.0

O app passa a levar a wslcsdk.dll consigo — o pacote Microsoft.WSL.Containers
é MIT, então redistribuir é permitido, e LICENSE.txt e NOTICE.txt vão junto.

São DUAS DLLs, 2.9.3 e 2.9.9, e a escolha é em tempo de execução, porque a
versão do SDK precisa acompanhar a do WSL. Isso foi medido, não suposto: com
WSL 2.9.4, o SDK 2.9.9 carrega, cria a sessão, lista imagens e então dá
segmentation fault em WslcGetSessionTerminationEvent. Nada no header denuncia
o problema — a declaração daquela função é byte a byte idêntica nas duas
versões, e os 18 structs também. A regra ficou conservadora: a DLL mais nova
que não passe da versão do WSL instalado; sem saber a versão, a mais antiga.
Errar para baixo custa recurso, errar para cima custa o processo.

A 2.9.9 também mudou duas assinaturas sem mudar nada visível
(WslcSessionAuthenticate ganhou tokenType, WslcInstallWithDependencies ganhou
components e options), o que corromperia login em registry e instalação
guiada em silêncio. O bindings.ts agora detecta a ABI pela presença do símbolo
WslcOpenContainer e adapta as duas chamadas.

Com isso a aba Sistema pode oferecer o seletor de DLL: o arquivo escolhido é
sondado na hora — carregado num binding próprio, lido e descarregado, sem
tocar na sessão viva — e só então gravado. Um arquivo errado é recusado ali,
em vez de virar um motor nativo quebrado na próxima abertura. A troca vale ao
reabrir o app, porque a sessão nativa segura handles da DLL atual.

No caminho, dois acertos: o registro de tipos koffi saiu de dentro do load
(era por nome, num namespace global, e impedia carregar uma segunda DLL), e o
campo sdkVersion virou wslVersion — a medição mostrou que WslcGetVersion
devolve a versão do WSL instalado, não a da DLL, e a UI dizia "SDK".

O ícone do app vem do icon.svg, rasterizado em .ico com 16/32/48/256.
…s antiga

Atualizar esta máquina para WSL 2.9.9 confirmou a hipótese do segfault — a
2.9.9 passou a funcionar inteira, com os 301 testes verdes, incluindo login em
registry e instalação guiada, que são justamente as duas rotas cujas
assinaturas mudaram.

E expôs um furo: a regra de compatibilidade é de mão dupla. SDK novo demais dá
segfault; SDK velho demais é recusado com WSLC_E_SDK_UPDATE_NEEDED em QUALQUER
chamada, inclusive no WslcGetVersion. Como o bootstrap perguntava a versão do
WSL à DLL mais antiga, num WSL 2.9.9 ele não obtinha resposta, caía na mais
antiga por precaução e deixava o app sem motor nativo.

Agora a sonda vai da mais nova para a mais antiga. A mais nova responde a
versão certa mesmo num WSL antigo (medido: a 2.9.9 respondeu 2.9.4 num WSL
2.9.4) — ela só quebra depois, ao mexer na sessão, que é do que a regra de
escolha protege.

O HRESULT de recusa também virou mensagem acionável, no status e na sonda do
seletor: em vez de "0x8004060B", diz que a DLL é antiga demais para o WSL e
aponta as duas saídas.
electron-builder gerando os dois alvos para x64, com as duas wslcsdk.dll em
extraResources (mais LICENSE e NOTICE, que a licença MIT do pacote exige levar
junto) e o koffi fora do asar, porque dlopen não enxerga arquivo dentro dele.

O app.asar caiu de 109 MB para 8,4 MB ao mover para devDependencies tudo o que
só o renderer usa. Estava tudo em dependencies, então viajava duas vezes: uma
embutida no bundle do Vite e outra em node_modules dentro do pacote. Só koffi
(nativo, carregado em tempo de execução) e zod (usado pelo main) precisam ficar.
Instalador e portátil saem com ~102 MB cada.

O release passou a empacotar ANTES de criar a tag: config de empacotamento
quebrada não pode deixar uma tag publicada sem binário. E ganhou um teste de
fumaça que abre o .exe de verdade e confere que o motor nativo achou a DLL em
resources/ — três coisas que só existem no app empacotado (asar, koffi
desempacotado, DLL fora de vendor/) e que o E2E, rodando contra out/, nunca
tocaria.

Verificado nesta máquina: o app instalado abre, escolhe a 2.9.9 pela regra de
versão, carrega o koffi do asar.unpacked e lista as imagens.
WslcOpenContainer levanta a limitação que o ROADMAP documentava: um container
criado numa execução pode ser reaberto por nome ou ID em outra. Medido: soltar
a sessão derruba o container para EXITED, mas o registro fica; reabrir devolve
um handle utilizável e o Start o põe de volta em RUNNING.

Então o app parou de apagar os containers na saída — o que só era necessário
porque, sem abrir por ID, eles virariam órfãos invisíveis no storage. Agora ele
lembra em disco (known.ts) os que criou e reabre na próxima listagem. O arquivo
mora dentro do storage da sessão, então o reset leva a memória junto, que é o
comportamento certo. Na ABI 2.9.3 nada muda: sem reabrir, apagar continua sendo
a única saída.

Continua não havendo enumeração de containers em nenhuma versão do SDK; é
justamente por isso que o app precisa lembrar os nomes.

Efeito colateral que só apareceu ao rodar a suíte: como fechar deixou de
apagar, sobras de execuções anteriores entravam na conta dos testes que
verificam quantidade. Os testes de integração agora limpam antes e depois.

Fecha a versão 0.2.0, com notas e bump.
…existe

Empacotar as DLLs no repositório quebrou o `describe.skipIf(locateWslcSdk() ===
null)`. Ele funcionava por acidente: como a DLL não era versionada, no CI ela
não existia e a suíte de integração pulava. Agora o arquivo existe em qualquer
runner — mas o WSL não, e 30 testes passaram a falhar no CI.

Presença de arquivo nunca foi a pergunta certa. `isNativeUsable()` carrega a
DLL e pede a versão, que é o que de fato determina se dá para testar contra o
SDK. Verificado apontando a 2.9.3 neste WSL 2.9.9, que a recusa: os 30 testes
pulam, em vez de falhar.
@blackfoxsoftware
blackfoxsoftware merged commit 2fd8eb1 into dev Sep 2, 2026
3 checks passed
@blackfoxsoftware
blackfoxsoftware deleted the feat/sdk-2.9.9-e-empacotamento branch September 2, 2026 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant