How To: Build examples using Visual Studio
Posted: Fri Nov 18, 2016 9:02 pm
It's been fun figuring out how to build the wimlib examples using Visual Studio so I thought I'd share. Here are the high level tasks that must be performed as of wimlib 1.10.0:
- Build wimlib from source (both i686 and x86_64 architectures).
- Create a new Win32 Console Application using Visual Studio 2013/2015.
- Add support for wimlib.
- Copy example and tweak main and wimlib_get_error_string() param.
Let's go!
1. To build wimlib from source, follow the instructions in README.WINDOWS.
Wait! Why am I building wimlib when all I want to do is simply reference the libwim-15.dll that ships in the release package? Because we need to tell the linker how to resolve external symbols, such as _wimlib_add_image. Without it, you will receive build errors like this:
error LNK2019: unresolved external symbol _wimlib_add_image referenced in function _wmain
We can use libwim.dll.a which is the archive that contains symbol definitions for library. This is not currently included in the release package so we need to build it. Remember to build for each (Windows relevant) architecture and keep a copy of each handy.
2. Create a new Win32 Console Application using Visual Studio 2013/2015.
FILE > New Project...
Templates > Visual C++ > Win32 > Win32 Console Application
Accept all wizard defaults.
Add x64 build support to our project:
BUILD > Configuration Manager > Active solution platform: > New > x64
3. Add support for wimlib.
Create two directories in the new console project directory (as peers to the .vcxproj and other files)
\i686
\x86_64
Copy the builds of libwim.dll.a generated in step 1 into each appropriate directory.
Now we need to tell the linker about these files, and align them with the build architectures.
PROJECT > Properties... > Platform > Win32
PROJECT > Configuration Properties > Linker > General > Additional Library Directories > .\i686
PROJECT > Configuration Properties > Linker > Input > Additional Dependencies > add libwim.dll.a to the list
OK
PROJECT > Properties... > Platform > x64
PROJECT > Configuration Properties > Linker > General > Additional Library Directories > .\x86_64
PROJECT > Configuration Properties > Linker > Input > Additional Dependencies > add libwim.dll.a to the list
OK
Note: When adding additional library dependencies, be sure to include a semicolon before and after. For example, the end of the dependency list should look something like ...odbccp32.lib;libwim.dll.a;%(AdditionalDependencies)
Copy wimlib.h from the wimlib source \include directory to the new console project directory (as a peer to the .vcxproj and other files). There are currently some nuances depending on what version of Visual Studio you use as discussed here.
Copy libwim-15.dll of each architecture to the corresponding Windows directory. For example:
wimlib-1.10.0-windows-i686-bin > WINDOWS\SysWOW64
wimlib-1.10.0-windows-x86_64-bin > WINDOWS\System32
4. Copy example and tweak main and wimlib_get_error_string() param.
Copy the contents of \examples\capturewim.c into your new console project's main .cpp file, overwriting all but the existing #include "stdafx.h" line at the top.
Modify main to support Microsoft's implementation of unicode/non-unicode builds:
From
int main(int argc, char **argv)
to
int _tmain(int argc, char* argv[])
If you don't, you'll get wimlib error 47 (file open) since the command line parameters will be passed into the functions incorrectly.
Cast ret to wimlib_error_code so wimlib_get_error_string doesn't complain:
From
wimlib_get_error_string(ret));
to
wimlib_get_error_string((wimlib_error_code)ret));
Here is the updated example:
Enjoy!
- Build wimlib from source (both i686 and x86_64 architectures).
- Create a new Win32 Console Application using Visual Studio 2013/2015.
- Add support for wimlib.
- Copy example and tweak main and wimlib_get_error_string() param.
Let's go!
1. To build wimlib from source, follow the instructions in README.WINDOWS.
Wait! Why am I building wimlib when all I want to do is simply reference the libwim-15.dll that ships in the release package? Because we need to tell the linker how to resolve external symbols, such as _wimlib_add_image. Without it, you will receive build errors like this:
error LNK2019: unresolved external symbol _wimlib_add_image referenced in function _wmain
We can use libwim.dll.a which is the archive that contains symbol definitions for library. This is not currently included in the release package so we need to build it. Remember to build for each (Windows relevant) architecture and keep a copy of each handy.
2. Create a new Win32 Console Application using Visual Studio 2013/2015.
FILE > New Project...
Templates > Visual C++ > Win32 > Win32 Console Application
Accept all wizard defaults.
Add x64 build support to our project:
BUILD > Configuration Manager > Active solution platform: > New > x64
3. Add support for wimlib.
Create two directories in the new console project directory (as peers to the .vcxproj and other files)
\i686
\x86_64
Copy the builds of libwim.dll.a generated in step 1 into each appropriate directory.
Now we need to tell the linker about these files, and align them with the build architectures.
PROJECT > Properties... > Platform > Win32
PROJECT > Configuration Properties > Linker > General > Additional Library Directories > .\i686
PROJECT > Configuration Properties > Linker > Input > Additional Dependencies > add libwim.dll.a to the list
OK
PROJECT > Properties... > Platform > x64
PROJECT > Configuration Properties > Linker > General > Additional Library Directories > .\x86_64
PROJECT > Configuration Properties > Linker > Input > Additional Dependencies > add libwim.dll.a to the list
OK
Note: When adding additional library dependencies, be sure to include a semicolon before and after. For example, the end of the dependency list should look something like ...odbccp32.lib;libwim.dll.a;%(AdditionalDependencies)
Copy wimlib.h from the wimlib source \include directory to the new console project directory (as a peer to the .vcxproj and other files). There are currently some nuances depending on what version of Visual Studio you use as discussed here.
Copy libwim-15.dll of each architecture to the corresponding Windows directory. For example:
wimlib-1.10.0-windows-i686-bin > WINDOWS\SysWOW64
wimlib-1.10.0-windows-x86_64-bin > WINDOWS\System32
4. Copy example and tweak main and wimlib_get_error_string() param.
Copy the contents of \examples\capturewim.c into your new console project's main .cpp file, overwriting all but the existing #include "stdafx.h" line at the top.
Modify main to support Microsoft's implementation of unicode/non-unicode builds:
From
int main(int argc, char **argv)
to
int _tmain(int argc, char* argv[])
If you don't, you'll get wimlib error 47 (file open) since the command line parameters will be passed into the functions incorrectly.
Cast ret to wimlib_error_code so wimlib_get_error_string doesn't complain:
From
wimlib_get_error_string(ret));
to
wimlib_get_error_string((wimlib_error_code)ret));
Here is the updated example:
Code: Select all
#include "stdafx.h"
#include "wimlib.h"
#include <stdio.h>
#define TO_PERCENT(numerator, denominator) \
((float)(((denominator) == 0) ? 0 : ((numerator) * 100 / (float)(denominator))))
static enum wimlib_progress_status
write_progress(enum wimlib_progress_msg msg,
union wimlib_progress_info *info, void *progctx)
{
switch (msg) {
case WIMLIB_PROGRESS_MSG_WRITE_STREAMS:
printf("Writing WIM: %.2f%% complete\n",
TO_PERCENT(info->write_streams.completed_bytes,
info->write_streams.total_bytes));
break;
default:
break;
}
return WIMLIB_PROGRESS_STATUS_CONTINUE;
}
// int main(int argc, char **argv)
int _tmain(int argc, char* argv[])
{
int ret;
WIMStruct *wim = NULL;
const char *srcdir;
const char *wimpath;
/* Check for the correct number of arguments. */
if (argc != 3) {
fprintf(stderr, "Usage: capturewim DIR WIM\n");
return 2;
}
srcdir = argv[1];
wimpath = argv[2];
/* Create a WIMStruct for a WIM. */
ret = wimlib_create_new_wim(WIMLIB_COMPRESSION_TYPE_LZX, &wim);
if (ret != 0) /* Always should check the error codes. */
goto out;
/* Register our progress function. */
wimlib_register_progress_function(wim, write_progress, NULL);
/* Add the directory tree to the WIMStruct as an image. */
ret = wimlib_add_image(wim, /* WIMStruct to which to add the image */
srcdir, /* Directory from which to add the image */
NULL, /* Name to give the image (NULL means none) */
NULL, /* Capture configuration structure (NULL means none) */
0); /* WIMLIB_ADD_FLAG_* flags (0 means all defaults) */
if (ret != 0)
goto out;
/* Write the WIM file. */
ret = wimlib_write(wim, /* WIMStruct from which to write a WIM */
wimpath, /* Path to write the WIM to */
WIMLIB_ALL_IMAGES, /* Image(s) in the WIM to write */
0, /* WIMLIB_WRITE_FLAG_* flags (0 means all defaults) */
0); /* Number of compressor threads (0 means default) */
out:
/* Free the WIMStruct. Has no effect if the pointer to it is NULL. */
wimlib_free(wim);
/* Check for error status. */
if (ret != 0) {
fprintf(stderr, "wimlib error %d: %s\n",
ret, wimlib_get_error_string((wimlib_error_code)ret));
}
/* Free global memory (optional). */
wimlib_global_cleanup();
return ret;
}