[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [rdiff-backup-users] Building librsync on Windows
From: |
Josh Nisly |
Subject: |
Re: [rdiff-backup-users] Building librsync on Windows |
Date: |
Mon, 23 Feb 2009 12:27:05 -0600 |
User-agent: |
Thunderbird 2.0.0.19 (X11/20090105) |
Probably the best documentation available is the build script that we
use for rdiff-backup on Windows. This script automates the librsync
build, including the fix needed for >4GB file support. (It uses the
Visual Studio Express 2008 for a compiler.) I've attached a (possibly
slightly outdated) copy.
Regarding packaging, I'd personally recommend using Py2exe to build an
executable, then use NSIS (nsis.sourceforge.net) for an installer. If
you have more specific questions with either of these programs, I'd be
happy to help you.
JoshN
Shawn Willden wrote:
This isn't really related to rdiff-backup, but I figure there's someone here
who knows the answers, so it's a good place to ask.
I'm working on an open source project (a backup project, actually, though one
that's substantially different from rdiff-backup -- if anyone is interested,
ask) and I'm using librsync to do forward deltas. I've been doing my
development on Linux and OS X, but it's time to start testing on Windows.
My problem is that I've found it a little bit difficult to build librsync on
Windows, so I'd like to know how you guys do it for your rdiff-backup Windows
binary. My app is written in Python, which is compiled with MSVC++, so I'm
trying to use the free-as-in-beer version that Microsoft provides to ensure
that my DLL is compatible. Is that what you use? Or do you use cygwin?
Which toolchain? With C code it shouldn't matter, I suppose.
I'd also appreciate any advice you have about packaging Python apps for
Windows.
If this isn't an appropriate discussion topic for this list, I'm happy to take
it off-list with the appropriate person.
Thanks,
Shawn.
import glob
import os
import shutil
import sys
import tarfile
import urllib
RDIFF_BACKUP_VERSION = '1.2.2'
RDIFF_BACKUP_NAME = 'rdiff-backup-'+RDIFF_BACKUP_VERSION
RDIFF_BACKUP_URL =
'http://savannah.nongnu.org/download/rdiff-backup/'+RDIFF_BACKUP_NAME+'.tar.gz'
LIBRSYNC_URL =
'http://superb-east.dl.sourceforge.net/sourceforge/librsync/librsync-0.9.7.tar.gz'
LIBRSYNC_VCPROJ_TEXT = r"""<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="librsync"
ProjectGUID="{B7D1448D-017B-4035-86A1-12B5B736101F}"
RootNamespace="librsync"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="4"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="popt; .\"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB;HAVE_STRERROR"
MinimalRebuild="true"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(OutDir)/rsync.lib"
IgnoreAllDefaultLibraries="true"
IgnoreDefaultLibraryNames=""
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\base64.c"
>
</File>
<File
RelativePath=".\buf.c"
>
</File>
<File
RelativePath=".\checksum.c"
>
</File>
<File
RelativePath=".\command.c"
>
</File>
<File
RelativePath=".\delta.c"
>
</File>
<File
RelativePath=".\emit.c"
>
</File>
<File
RelativePath=".\fileutil.c"
>
</File>
<File
RelativePath=".\popt\findme.c"
>
</File>
<File
RelativePath=".\hex.c"
>
</File>
<File
RelativePath=".\isprefix.c"
>
</File>
<File
RelativePath=".\job.c"
>
</File>
<File
RelativePath=".\mdfour.c"
>
</File>
<File
RelativePath=".\mksum.c"
>
</File>
<File
RelativePath=".\msg.c"
>
</File>
<File
RelativePath=".\netint.c"
>
</File>
<File
RelativePath=".\patch.c"
>
</File>
<File
RelativePath=".\popt\popt.c"
>
</File>
<File
RelativePath=".\popt\poptconfig.c"
>
</File>
<File
RelativePath=".\popt\popthelp.c"
>
</File>
<File
RelativePath=".\popt\poptparse.c"
>
</File>
<File
RelativePath=".\prototab.c"
>
</File>
<File
RelativePath=".\rdiff.c"
>
</File>
<File
RelativePath=".\readsums.c"
>
</File>
<File
RelativePath=".\rollsum.c"
>
</File>
<File
RelativePath=".\scoop.c"
>
</File>
<File
RelativePath=".\search.c"
>
</File>
<File
RelativePath=".\snprintf.c"
>
</File>
<File
RelativePath=".\stats.c"
>
</File>
<File
RelativePath=".\stream.c"
>
</File>
<File
RelativePath=".\sumset.c"
>
</File>
<File
RelativePath=".\trace.c"
>
</File>
<File
RelativePath=".\tube.c"
>
</File>
<File
RelativePath=".\util.c"
>
</File>
<File
RelativePath=".\version.c"
>
</File>
<File
RelativePath=".\whole.c"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
"""
LIBRSYNC_SLN_TEXT = r"""Microsoft Visual Studio Solution File, Format Version
10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "librsync",
"librsync.vcproj", "{B7D1448D-017B-4035-86A1-12B5B736101F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B7D1448D-017B-4035-86A1-12B5B736101F}.Debug|Win32.ActiveCfg =
Debug|Win32
{B7D1448D-017B-4035-86A1-12B5B736101F}.Debug|Win32.Build.0 =
Debug|Win32
{B7D1448D-017B-4035-86A1-12B5B736101F}.Release|Win32.ActiveCfg
= Release|Win32
{B7D1448D-017B-4035-86A1-12B5B736101F}.Release|Win32.Build.0 =
Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
"""
LIBRSYNC_PATCH_TEXT="""diff -w -Nur librsync-0.9.7/buf.c librsync-0.9.7dev/buf.c
--- librsync-0.9.7/buf.c 2004-02-07 18:17:57.000000000 -0500
+++ librsync-0.9.7-win/buf.c 2008-11-20 12:28:23.000000000 -0500
@@ -59,6 +59,11 @@
#define fseek fseeko
#endif
+#ifdef NEED_FSEEKI64
+int __cdecl _fseeki64(FILE *, __int64, int);
+#define fseek _fseeki64
+#endif
+
/**
* File IO buffer sizes.
*/
diff -urN librsync-0.9.7/mdfour.h librsync-0.9.7dev/mdfour.h
--- librsync-0.9.7/mdfour.h 2004-02-07 18:17:57.000000000 -0500
+++ librsync-0.9.7dev/mdfour.h 2006-03-06 03:21:46.000000000 -0500
@@ -24,7 +24,7 @@
#include "types.h"
struct rs_mdfour {
- int A, B, C, D;
+ unsigned int A, B, C, D;
#if HAVE_UINT64
uint64_t totalN;
#else
diff -urN librsync-0.9.7/patch.c librsync-0.9.7dev/patch.c
--- librsync-0.9.7/patch.c 2004-09-17 17:35:50.000000000 -0400
+++ librsync-0.9.7dev/patch.c 2006-03-06 03:21:06.000000000 -0500
@@ -214,12 +214,12 @@
void *buf, *ptr;
rs_buffers_t *buffs = job->stream;
- len = job->basis_len;
-
/* copy only as much as will fit in the output buffer, so that we
* don't have to block or store the input. */
- if (len > buffs->avail_out)
+ if (job->basis_len > buffs->avail_out)
len = buffs->avail_out;
+ else
+ len = job->basis_len;
if (!len)
return RS_BLOCKED;
"""
CONFIG_H_TEXT = """
#define SIZEOF_UNSIGNED_INT 4
#define PACKAGE "librsync"
#define VERSION "0.9.7"
#define RS_CANONICAL_HOST "librsync.sourceforge.net"
#define inline
#define NEED_FSEEKI64
"""
class BuildError(Exception):
pass
def copy(src_pattern, dest_dir):
if '*' in src_pattern:
files = glob.glob(src_pattern)
else:
files = [src_pattern]
for file in files:
shutil.copyfile(file, os.path.join(dest_dir,
os.path.basename(file)))
def unzip(src_file, target_dir):
print 'Extracting %s...' % src_file
extension = src_file.rpartition('.')[2]
tar = tarfile.open(src_file, 'r:'+extension)
for tarinfo in tar:
dest_path = os.path.join(target_dir, tarinfo.name.replace('/',
os.sep))
if tarinfo.isreg():
tar.extract(tarinfo, target_dir)
elif tarinfo.isdir():
if not os.path.isdir(dest_path):
os.mkdir(dest_path)
elif tarinfo.issym():
pass # We don't care about symlinks
else:
raise ValueError, 'Unhandled .tar.gz file:'+str(tarinfo)
tar.close()
def verify_env(require_cvs):
for path in os.environ['PATH'].split(';'):
if os.path.exists(os.path.join(path, 'MSBuild.exe')):
break
else:
raise BuildError, '''This script must be run from \
the Visual Studio 2008 Commandline.'''
if require_cvs:
for path in os.environ['PATH'].split(';'):
if os.path.exists(os.path.join(path, 'cvs.exe')):
break
else:
raise BuildError, '''Cvs.exe (CVSNT) must be in the
path.'''
def download_file(url, target_dir):
filename = os.path.basename(url)
target_name = os.path.join(target_dir, filename)
if not os.path.exists(target_name):
print 'Downloading %s...' % url
urllib.urlretrieve(url, target_name)
unzip(target_name, target_dir)
def write_text(filepath, text):
file = open(filepath, 'w')
file.write(text)
file.close()
def build_librsync(root_dir):
# Download package if necessary
download_file(LIBRSYNC_URL, root_dir)
# Add in support files
librsync_dir = os.path.join(root_dir, 'librsync-0.9.7')
write_text(os.path.join(librsync_dir, 'librsync.sln'),
LIBRSYNC_SLN_TEXT)
write_text(os.path.join(librsync_dir, 'librsync.vcproj'),
LIBRSYNC_VCPROJ_TEXT)
write_text(os.path.join(librsync_dir, 'config.h'), CONFIG_H_TEXT)
# Patch for 4GB support
large_file_patch = os.path.join(librsync_dir, 'lfs_support.patch')
write_text(large_file_patch, LIBRSYNC_PATCH_TEXT)
os.chdir(root_dir)
if os.system('patch.exe -p0 < %s' % large_file_patch):
raise BuildError, 'Unable to patch librsync.'
# Build
sln_path = os.path.join(librsync_dir, 'librsync.sln')
if os.system('MSBuild.exe %s /t:Build /p:Configuration=Release' %
sln_path):
raise BuildError, 'Unable to build librsync.'
# Copy built library to where rdiff-backup's setup.py expects it
output_dir = os.path.join(librsync_dir, 'lib')
if not os.path.isdir(output_dir):
os.mkdir(output_dir)
lib_path = os.path.join(librsync_dir, 'Release', 'rsync.lib')
copy(lib_path, output_dir)
# Copy include files to where rdiff-backup expects them
include_dir = os.path.join(librsync_dir, 'include')
if not os.path.isdir(include_dir):
os.mkdir(include_dir)
for file in ('librsync.h', 'librsync-config.h'):
copy(os.path.join(librsync_dir, file), include_dir)
def build_rdiff_backup(use_cvs, rebuild, root_dir, output_dir):
rdiff_dir = os.path.join(root_dir, 'rdiff-backup')
librsync_dir = os.path.join(root_dir, 'librsync-0.9.7')
# Check out rdiff-backup
if rebuild:
if os.path.exists(rdiff_dir):
shutil.rmtree(rdiff_dir)
if use_cvs:
if not os.path.isdir(rdiff_dir):
os.chdir(root_dir)
if os.system('cvs -z3
-d:pserver:address@hidden:/sources/rdiff-backup co .'):
raise BuildError, 'Unable to check out
rdiff-backup!'
# Patch rdiff-backup
os.chdir(rdiff_dir)
patch_exe = 'patch.exe'
for patch in ('rdiff-backup-windows-drive.patch',):
patch_path = os.path.join(root_dir, '..', patch)
print 'patching:', patch
if os.system('%s -N -p0 < %s' % (patch_exe,
patch_path)):
raise BuildError, 'Unable to patch
rdiff-backup!'
# Make an rdiff-backup dist package
os.chdir(rdiff_dir)
if os.system('python dist\\makedist ' + RDIFF_BACKUP_VERSION):
raise BuildError, 'Unable to make rdiff-backup dist
package.'
# There is now a built version in the rdiff-backup dir.
# Extract it, build it, and copy the exe to output_dir.
rdiff_output_name = 'rdiff-backup-'+RDIFF_BACKUP_VERSION
target_dir = os.path.join(rdiff_dir, rdiff_output_name)
if os.path.exists(target_dir):
shutil.rmtree(target_dir)
rdiff_tar = target_dir + '.tar.gz'
unzip(rdiff_tar, rdiff_dir)
else:
if not os.path.exists(rdiff_dir):
os.mkdir(rdiff_dir)
download_file(RDIFF_BACKUP_URL, rdiff_dir)
rdiff_output_name = RDIFF_BACKUP_NAME
rdiff_output_dir = os.path.join(rdiff_dir, rdiff_output_name)
os.chdir(rdiff_output_dir)
# Build rdiff-backup
if os.system('setup.py build --librsync-dir=%s --lflags=%s' % \
(librsync_dir, '"/NODEFAULTLIB:libcmt.lib
msvcrt.lib"')):
raise BuildError, 'Unable to build rdiff-backup.'
if os.system('setup.py py2exe --single-file > NUL'):
raise BuildError, 'Unable to rdiff-backup via py2exe.'
copy(os.path.join(rdiff_output_dir, 'dist', 'rdiff-backup.exe'),
output_dir)
if __name__ == '__main__':
root_dir = os.path.dirname(__file__)
target_dir = os.path.join(root_dir, 'temp')
output_dir = os.path.join(root_dir, 'output')
rebuild = '--rebuild' in sys.argv[1:]
use_cvs = '--cvs' in sys.argv[1:]
for dir in (target_dir, output_dir):
if not os.path.isdir(dir):
os.makedirs(dir)
verify_env(use_cvs)
build_librsync(target_dir)
build_rdiff_backup(use_cvs, rebuild, target_dir, output_dir)