Usando a LIBC nativa do Windows

Data: 2007-11-21
Categorias: C++

Por padrão, todo projeto no Visual Studio depende da LIBC. Isso quer dizer que, mesmo que você não use nem um mísero printf em todos os projetos criados, está atrelado a essa dependência. Em tempos onde fazer um "Hello World" pode custar 56 KB em Release - Visual Studio 2005, configuração padrão sem "buffer security check" - vale a pena economizar alguns KBytes que não se vão usar. Principalmente se essa possibilidade existe desde o cavernoso Windows 95.

Como fazer um projeto de Hello World

  1. Crie um novo projeto console Win32 vazio (File, New, Project, blá blá blá)
  2. Crie um arquivo CPP no projeto (Project, Add New Item, etc)
  3. Crie um código parecido com o código abaixo (parecido == usando apenas LIBC básica)
  4. Troque a configuração para Release, pois Debug não tem graça (Build, Configuration Manager, Release)
  5. Mude a runtime para estática (Project, Properties, C/C++, Code Generation, Multi-threaded)
  6. Compile e link (Build, Build Solution)

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <string.h>
 
int main()
{
	printf("oi, mundo!");
}

Pronto, após esses passos temos um projeto ordinário que compila um executável console ordinário que não depende de runtimes novas com exatos (pelo menos aqui) 57.344 bytes.

Agora a parte divertida =).

Como gerar um .LIB de uma DLL de terceiros

Desde o Windows 95, existe uma DLL com a maioria das funções da LIBC disponíveis para link dinâmico. Só que, com o uso padrão do Visual C++, é usada sempre a biblioteca que vem junto com o ambiente, com suas trocentas funções (e conseqüentes bytes enche-lingüiça). Porém, é possível utilizar diretamente a msvcrt.dll distribuída no diretório do sistema se criarmos uma LIB de importação para ela.

  1. Copie a msvcrt.dll diretamente de um Windows 95 (diretório System) para evitar funções que não existam desde a primeira distribuição
  2. Utilizando essa versão da DLL e o prompt de comando do Visual Studio, execute:
    REM
    REM Isso gera um arquivo def em estado bruto
    REM
    DUMPBIN /EXPORTS msvcrt.dll > msvcrt.def
  3. Utilizando o editor do seu coração, retire as linhas desnecessárias (aquelas do início do comando)
  4. Retire as colunas desnecessárias (todas menos a com o nome das funções)
  5. Retire os nomes bizarros que você não vai usar (todos os primeiros e que começam com '?')
  6. Ainda no ambiente console do VC execute o seguinte comando:
    REM
    REM Isso gera um arquivo .lib para importar as funções da DLL
    REM
    LIB /DEF:msvcrt.def

Nada nessa mão, nem nessa. Mas no system32...

Ótimo. Geramos a LIB que precisávamos e agora só falta integrar com o projeto. Para isso, mais alguns passos:

  1. Copie o msvcrt.lib para o diretório do projeto.
  2. No projeto, coloque o arquivo na lista de LIBs a serem incluídas (Properties, Linker, Input, Additional Dependencies).
  3. Ignore o resto das LIBs colocadas por padrão no projeto (Linker, Input, Ignore All Default Libraries).
  4. Ignore as firulas de checagem (C/C++, Code Generation, Buffer Security Check, e Basic Runtime Checks em Debug).
  5. Explicite o entry-point para a função main (Linker, Advanced, Entry Point).
  6. Compile e linke!
------ Rebuild All started: Project: NativeC, Configuration: Release Win32 ------
Deleting intermediate and output files for project 'NativeC', configuration 'Release|Win32'
Compiling...
NativeC.cpp
Linking...
Generating code
Finished generating code
Embedding manifest...
Build Time 0:00
Build log was saved at "file://c:ProjectsTempNativeCReleaseBuildLog.htm"
NativeC - 0 error(s), 0 warning(s)
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
Size: 2.944 bytes.

E agora o tamanho final de nosso executável passou para espantosos 2KB! Isso a princípio parece ótimo e dá vontade de usar em todos os projetos, mas existe um porém ainda não resolvido: as limitações da falta de um runtime. Para isso que existe a próxima seção.

Disclaimer

Essa é uma solução bem bobinha que não tem nada a ver com uma solução profissional 100% garantida e com suporte técnico 24 horas. Algumas coisas não vão funcionar, como inicialização de variáveis estáticas, exceções, redirecionamento de entrada/saída, etc. Contudo, para projetos simples e pequenos, isso não deverá ser um problema. No entanto, eu não garanto qualquer coisa que advier de compilações inspiradas neste artigo.

Para quem é viciado por economia de espaço

9 respostas para “Usando a LIBC nativa do Windows”

  1. Yorick Diz:

    Recentemente encontrei isso, acho q tem a v :)
    http://kobyk.wordpress.com/2007/07/20/dynamically-linking-with-msvcrtdll-using-visual-c-2005/
    http://nn1234.wordpress.com/2008/04/11/vc-90-msvcrtdll-windows-95/

  2. Yorick Diz:

    Testei o metodo do Koby e funciona muito bem, como Koby menciona em seu site, eh bem menos sujeito a erros para programas mais complexos, estou usando em compilações em modo release, em debug mode continuo com o msvcr90d.dll do Visual C++ 2008. Vinculação à msvcp que contém C++ stuff como STL não é possivel de forma dinâmica utilizando o mesmo método, se for seguidos os passos do WDK é possível a vinculação estática. A seguir os procedimentos que usei para poder usar a crt dinâmica + stl estática:

    Additional Include Directories:
    C:\WinDDK\\inc\crt;C:\WinDDK\\inc\api;C:\WinDDK\\inc\api\crt\stl70

    Preprocessor Definitions
    WIN32;NDEBUG;_CONSOLE;_STATIC_CPPLIB;_STL70_

    Additional Library Directories
    C:\WinDDK\\lib\crt\i386;C:\WinDDK\\lib\w2K\i386

    Generate Manifest
    No

    Additional Dependencies
    msvcrt_win2000.obj ntstc_msvcrt.lib msvcprt_btowc.lib

  3. Wanderley Caloni Diz:

    Desculpe a ignorância, mas quem é esse Koby? Tem algum linque para esse método?

    []s

  4. Yorick Diz:

    errr, eu passei o link no primeiro comentario, num faz sentido o segundo sem o primeiro, mas tah aqui ele denovo:

    Recentemente encontrei isso, acho q tem a v :)
    http://kobyk.wordpress.com/2007/07/20/dynamically-linking-with-msvcrtdll-using-visual-c-2005/
    http://nn1234.wordpress.com/2008/04/11/vc-90-msvcrtdll-windows-95/

  5. Yorick Diz:

    ah, o primeiro naum tah aprovado ainda, deve ser por isso

  6. George Luiz Bittencourt Diz:

    Olá,

    Com o parâmetro /MD do compilador é possível fazer isso sem a necessidade de criar uma lib.

    -George

  7. Wanderley Caloni Diz:

    Olá, George.

    O parâmetro /MD cria um projeto que depende da DLL de runtime do Visual Studio (a msvcXX.dll, sendo XX a versão atual). Esse artigo demonstra como criar um projeto que não dependa de nenhum tipo de LIB estática ou distribuída pelo Visual Studio. No entanto, os projetos compilados com essa solução passarão a depender da DLL de runtime localizada no diretório de sistema do próprio Windows.

    []s

  8. George Luiz Bittencourt Diz:

    Olá,

    Concordo com você, realmente desse jeito não irá depender de nenhuma LIB do Visual C, seja ela estática ou dinâmica.

    Alêm do tamanho reduzido outra vantagem de se linkar de forma dinâmica é que uma eventual atualização no runtime beneficia todos os programas que utilizem essa DLL. De forma estática isso não é possível já que o conteúdo dos arquivos OBJ (archive members da LIB) é copiado para o módulo final.

    A propósito, você trabalha com C/C++ em SP? Como que é o mercado ai nesse ramo? Tem muita demanda?

    Valeu e o seu artigo ficou muito bom! Legal também é a LIBCTINY.LIB do Pietrek.

    []s

    -George

  9. Wanderley Caloni Diz:

    Sim, trabalho atualmente em São Paulo, Brasil. O mercado? Não sou uma pessoa muito indicada para falar sobre isso, pois trabalhei até hoje apenas em dois lugares. O que ouvimos falar quase sempre no grupo de oportunidades C++ são de empregos para essa área, quase a maioria.

    []s

Deixe uma resposta