Jitsi Sip Communicator Source Code Build Guide for Windows

This guide will show how to build Jitsi from source into a Windows installable application in 32 and 64bit form.  It assumes the development environment is 64bit.  Although we tried to make it as simple as possible, it is still rather involved.

Development software

Windows 7/8/10 x64
WiX Toolset v3.11.1701
Apache Ant v1.10.1
Java SE Development Kit 8u131 x64
Java SE Runtime Environment 8u131 x86 and x64
TDM64-GCC MinGW Compiler v5.1.0
Eclipse IDE for Java Developers x64, Neon 3 version

Install

WiX Toolset

Download the binaries.zip file and install contents into C:\wix311.

Apache Ant

Download and unzip the contents of the apache-ant-1.10.1 folder to a newly created folder C:\ant.

Java Development Kit

Install JDK v8 using defaults. 

Install JRE v8u131 for creating the embedded Java environment later on in this procedure.  The 32bit app needs JRE x86 and the 64bit version needs JRE x64.

MingGW Compiler

For TDM64-GCC installer select MinGW-w64/TDM64 option and install to C:\mingw\x64.  The official MinGW-w64 installer can also be used.  We prefer the TDM64-GCC installer.

Run the installer again and select MinGW-TDM (32 bit).  Change install directory to C:\mingw\x86 and install using defaults.  Alternatively use the official MinGW installer.
 
Rename C:\mingw\x86\bin\mingw32-make.exe to make.exe.
Do the same thing in C:\mingw\x64\bin.

Eclipse

Install using the windows installer.  When starting Eclipse it will ask for a workspace location.  For this guide we will be using  C:\workspace

Select the Workbench icon at the upper right which brings us to the main default workspace area.

eclipse main workspace

At upper left select File > Import > Git > Projects from Git > Next > Clone URI > Next

Enter the URI for the Jitsi project which should be https://github.com/jitsi/jitsi.git

source git repository

Using defaults select Next > Next and change destination directory which for this guide will be C:\workspace\jitsi

Import GIT project

Using defaults again select Next at which point it will download the project.  Select the Next button again and then the Finish button.  Again leaving everything at defaults.

This is what our working environment should now look like

Jitsi working environment

Directory structure

When all required software is installed the directory structure should look like this.

C:\
├───Program Files
│   └───Java
│       ├───jdk1.8.0_131
│       └───jre1.8.0_131
├───Program Files (x86)
│   └───Java
│       └───jre1.8.0_131
├───ant
│   └───bin
├───mingw
│   ├───x64
│   |   └───bin
│   └───x86
│       └───bin
├───wix311
└───workspace
    └───jitsi

Configure

Windows Environment Variables

On Windows 7 go to Start > Control Panel > System and Security > System > Advanced system settings > Advanced > Environment variables.  

On Windows 10 the first part is Start > All Apps > Windows System > Control Panel > etc. etc.

System variables > New

Variable name: ANT_HOME
Variable value: C:\ant

Variable name: JAVA_HOME
Variable value: C:\Program Files\Java\jdk1.8.0_131

Scroll down to Path and add the following to the end.  Don't forget the ; at the beginning. 

%ANT_HOME%\bin;%JAVA_HOME%\bin;C:\mingw\x86\bin;C:\mingw\x64\bin;C:\wix311
Some of these things may have already been added by the installers.

Windows Environment Variables

If Eclipse is already running it must be restarted after environment variable changes.

Eclipse Workspace

From top menu Run > Run Configurations > Java Application > Press the "New" button at the upper left and fill in the details

Name Tab: Jitsi , Project: jitsi, Main class: net.java.sip.communicator.launcher.SIPCommunicator

Arguments Tab: > VM Arguments: 

-Dfelix.config.properties=file:lib/felix.client.run.properties
-Djava.util.logging.config.file=lib/logging.properties
-Dnet.java.sip.communicator.SC_HOME_DIR_NAME=Jitsi-dev

Classpath Tab: > Click "User Entries" > Click "Advanced" button > Select "Add Folders" > Select jitsi/lib

Run configuration classpath

Environment Tab: > Click "New"

Name: path
Value: %path%;./lib/native/windows-64
Run configuration envionment tab

Save the Run configuration by pressing the Apply button.

Setup Ant in Eclipse

From the top menu select Window > Show View > Ant

At which point you will see an Ant tab appear in the middle right section of our workspace.  Now drag the build.xml file from the expanded left hand column file list over to this right hand area.  When done your fully configured workspace should look as follows.

eclipse configured workspace

Build and Run Jitsi

According to this Jitsi document on setting up Eclipse, you need to run Ant make-and-deploy the first time this is all set up.  To do that right click make-and-deploy > Run As > 1 Ant Build in the right hand Ant section.  After that you can just run make after changes.  

Now try running Jitsi inside the development environment.  In the right hand Ant section right click on run > Run As > 1 Ant Build.  You should see the Jitsi GUI start up.  Do not be too concerned with any warning messages in the console.

Jitsi running in development environment

Create Embedded Java Runtime files

To install and run Jitsi, without knowing the state of the Windows OS it is being installed on, we will embed JRE with our Jitsi installer.  This is the same way the official Jitsi installer does it.

Assuming JRE v8u131 x64 has been installed in the default location we simply right click on the C:\Program Files \Java\jre1.8.0_131 folder and copy/paste to desktop.  Rename the folder jre, right click and select Send to > compressed (zipped) folder.  Rename the zipped file something like jre-8u131-windows-x64.zip.  Do the same for the 32bit version in the Program Files (x86) folder.  

Create a folder C:\Install and place both zipped files in there.  Now edit .\resources\install\installers.properties and rename the zip file names accordingly.

Ant Build Configuration

To customize the windows installer edit .\resources\install\ant-build-config.properties.  The existing configuration should make it self explanatory.  To make the installer work just like the installer on the jitsi website you need to add splashscreen.enable=true to the bottom.

build.xml configuration

Make one change to .\resources\install\build.xml to change the assumed location of the WiX folder. Around line 628

<property name="wix.home" value="C:\wix311" />
 

Alternatively, this can be done in Eclipse.  This will override the value in the above file.  From the top menu goto Run > External Tools > External Tools Configuration > Ant Build > Jitsi build.xml > Main

Arguments: -Dwix.home=C:\wix311

Makefile Configuration

We have to make changes to the 3 main Makefiles for them to work properly.  Watch out for the wordwrap.  The way it is displayed on our website would be incorrect if cut/paste directly into the makefiles.  Compare to the original makefiles first and correct as necessary.

When adding the echo statements to the makefiles, make sure the lines are indented with tabs, not spaces.  The compile will fail if any makefile commands are not indented with tabs.

Run Makefile

Changes to run Makefile include removing "" on the 2 target.dir statements, removing -O2 compiler flag to prevent crashing on startup, separating single echo statement (which does not work) into separate lines.

# .\src\native\windows\run\Makefile
#
# Make sure all indented lines use tab indent, not spaces.
#

MINGW_HOME ?= C:/mingw
PRODUCTNAME ?= Jitsi
COMPANYNAME ?= jitsi.org
PRODUCTBUILDVERSION ?= 1.0.0.0
PRODUCTBUILDVERSION_COMMA ?= 1,0,0,0
TARGET_BASENAME ?= run
TARGET_DIR ?= ../../../../release/windows/tmp

ifeq ($(wildcard /bin/cygpath.*),/bin/cygpath.exe)
    target.dir := $(shell cygpath --mixed "$(TARGET_DIR)")
    cygwin.target.dir := $(shell cygpath --unix "$(TARGET_DIR)")
else
    target.dir := $(TARGET_DIR)
    cygwin.target.dir := $(TARGET_DIR)
endif

CC = $(MINGW_HOME)/bin/gcc.exe
CPPFLAGS := $(CPPFLAGS) \
    -Wall -Wreturn-type \
    -DPSAPI_VERSION=1 \
    -DWINVER=0x0502 -D_WIN32_WINNT=0x0502 \
    -I$(target.dir) \
    -I"$(JAVA_HOME)/include" -I"$(JAVA_HOME)/include/win32"
LDFLAGS = -mwindows
LIBS = -ladvapi32 -lpsapi

MACHINE = $(shell $(CC) -dumpmachine)
WINDRES = $(MINGW_HOME)/bin/windres.exe
ifneq ("x$(MACHINE)","x")
ifeq ($(wildcard $(MINGW_HOME)/bin/$(MACHINE)-windres.*),$(MINGW_HOME)/bin/$(MACHINE)-windres.exe)
    WINDRES = $(MINGW_HOME)/bin/$(MACHINE)-windres.exe
endif
endif

$(cygwin.target.dir)/$(TARGET_BASENAME).exe: $(cygwin.target.dir)/config.h registry.c run.c $(cygwin.target.dir)/run.res ../setup/nls.c
    $(CC) $(CPPFLAGS) registry.c run.c $(target.dir)/run.res ../setup/nls.c $(LDFLAGS) -o $(target.dir)/$(TARGET_BASENAME).exe $(LIBS)
    -$(MINGW_HOME)/$(MACHINE)/bin/strip.exe $(target.dir)/$(TARGET_BASENAME).exe

.PHONY: $(cygwin.target.dir)/config.h

$(cygwin.target.dir)/config.h:
    -rm.exe -f ../../../../resources/install/windows/config.h
    echo #define PRODUCTNAME "$(PRODUCTNAME)" > $(cygwin.target.dir)/config.h
    echo #define COMPANYNAME "$(COMPANYNAME)" >> $(cygwin.target.dir)/config.h
    echo #define PRODUCTBUILDVERSION "$(PRODUCTBUILDVERSION)" >> $(cygwin.target.dir)/config.h
    echo #define PRODUCTBUILDVERSION_COMMA $(PRODUCTBUILDVERSION_COMMA) >> $(cygwin.target.dir)/config.h
    echo #define TARGET_BASENAME "$(TARGET_BASENAME)" >> $(cygwin.target.dir)/config.h
    echo #define TARGET_BASENAME_EXE "$(TARGET_BASENAME).exe" >> $(cygwin.target.dir)/config.h

$(cygwin.target.dir)/run.res: $(cygwin.target.dir)/config.h run.rc
    $(WINDRES) -I../../../../resources/install/windows -I$(target.dir) run.rc -O coff -o $(target.dir)/run.res

Setup Makefile

Changes to setup Makefile include removing "" on the 2 target.dir statements, a working ARCH determination (assigns "x86" if running wix with mingw installed, assigns "x64" if wix-64 with mingw-w64 installed) , separating single echo statement into individual lines.

# .\src\native\windows\setup\Makefile
#
# Make sure all indented lines use tab indent, not spaces
#

BZ2_HOME ?= .
LZMA_HOME ?= .
MINGW_HOME ?= C:/mingw
PRODUCTNAME ?= Jitsi
PRODUCTBUILDVERSION ?= 1.0.0.0
TARGET_BASENAME ?= setup
TARGET_DIR ?= ../../../../release/windows/tmp

ifeq ($(wildcard /bin/cygpath.*),/bin/cygpath.exe)
    target.dir := $(shell cygpath --mixed "$(TARGET_DIR)")
    cygwin.target.dir := $(shell cygpath --unix "$(TARGET_DIR)")
else
    target.dir := $(TARGET_DIR)
    cygwin.target.dir := $(TARGET_DIR)
endif

CC = $(MINGW_HOME)/bin/gcc.exe

CPPFLAGS = \
    -O2 \
    -Wall -Wreturn-type \
    -DWINVER=0x0502 -D_WIN32_WINNT=0x0502 \
    -I$(target.dir) \
    -DBSPATCH_API_STATIC -DBZ2_API_STATIC -I. -I$(BZ2_HOME)/include -I$(BZ2_HOME) \
    -DLZMA_API_STATIC -I$(LZMA_HOME)/include -I$(LZMA_HOME)/api \
    -I../run
LDFLAGS = \
    -mwindows \
    -L$(BZ2_HOME)/lib/$(ARCH) -L$(BZ2_HOME) \
    -L$(LZMA_HOME)/lib/$(ARCH) -L$(LZMA_HOME)/.libs
LIBS = -ladvapi32 -lbz2 -llzma -lole32 -lshell32

MACHINE = $(shell $(CC) -dumpmachine)

ifneq (,$(findstring x86_64-,$(MACHINE)))
    ARCH = x64
else ifneq (,$(findstring i.86-,$(MACHINE)))
    ARCH = x86
else ifeq ("$(MACHINE)","mingw32")
    ARCH = x86
endif

WINDRES = $(MINGW_HOME)/bin/windres.exe
ifneq ("x$(MACHINE)","x")
ifeq ($(wildcard $(MINGW_HOME)/bin/$(MACHINE)-windres.*),$(MINGW_HOME)/bin/$(MACHINE)-windres.exe)
    WINDRES = $(MINGW_HOME)/bin/$(MACHINE)-windres.exe
endif
endif

ifdef PACKAGECODE
    DEFINE_PACKAGECODE = define PACKAGECODE "$(strip $(PACKAGECODE))"
else
    DEFINE_PACKAGECODE = undef PACKAGECODE
endif
ifdef PACKAGESIZE
    DEFINE_PACKAGESIZE = define PACKAGESIZE $(strip $(PACKAGESIZE))
else
    DEFINE_PACKAGESIZE = undef PACKAGESIZE
endif

$(cygwin.target.dir)/$(TARGET_BASENAME).exe: bspatch.c $(cygwin.target.dir)/config.h lasterror.c nls.c ../run/registry.c setup.c $(cygwin.target.dir)/setup.res
    $(CC) $(CPPFLAGS) bspatch.c lasterror.c nls.c ../run/registry.c setup.c $(target.dir)/setup.res $(LDFLAGS) -o $(target.dir)/$(TARGET_BASENAME).exe $(LIBS)
    -$(MINGW_HOME)/$(MACHINE)/bin/strip.exe $(target.dir)/$(TARGET_BASENAME).exe

.PHONY: $(cygwin.target.dir)/config.h

$(cygwin.target.dir)/config.h:
    -rm.exe -f ../../../../resources/install/windows/config.h
    echo #define PRODUCTNAME "$(PRODUCTNAME)" > $(cygwin.target.dir)/config.h
    echo #$(DEFINE_PACKAGECODE) >> $(cygwin.target.dir)/config.h
    echo #$(DEFINE_PACKAGESIZE) >> $(cygwin.target.dir)/config.h
    echo #define PRODUCTBUILDVERSION "$(PRODUCTBUILDVERSION)" >> $(cygwin.target.dir)/config.h

$(cygwin.target.dir)/setup.res: $(cygwin.target.dir)/config.h setup.rc
    $(WINDRES) -I../../../../resources/install/windows -I$(target.dir) setup.rc -O coff -o $(target.dir)/setup.res

Cleansweep Makefile

Changes to cleansweep Makefile include removing "" from the 2 target.dir statements and separating out the echo statments.

#.\src\native\windows\setup\cleansweep\Makefile
#
# Make sure all indented lines use tab indent, not spaces
#

MINGW_HOME ?= C:/mingw
PRODUCTNAME ?= Jitsi
TARGET_BASENAME ?= cleansweep
TARGET_DIR ?= ../../../../../release/windows/tmp

ifeq ($(wildcard /bin/cygpath.*),/bin/cygpath.exe)
    target.dir := $(shell cygpath --mixed "$(TARGET_DIR)")
    cygwin.target.dir := $(shell cygpath --unix "$(TARGET_DIR)")
else
    target.dir := $(TARGET_DIR)
    cygwin.target.dir := $(TARGET_DIR)
endif

CC = $(MINGW_HOME)/bin/gcc.exe
CPPFLAGS = \
    -O2 \
    -Wall -Wreturn-type \
    -DWINVER=0x0502 -D_WIN32_WINNT=0x0502 \
    -I$(target.dir)
LDFLAGS = -mwindows
LIBS = -lshell32

MACHINE = $(shell $(CC) -dumpmachine)
WINDRES = $(MINGW_HOME)/bin/windres.exe
ifneq ("x$(MACHINE)","x")
ifeq ($(wildcard $(MINGW_HOME)/bin/$(MACHINE)-windres.*),$(MINGW_HOME)/bin/$(MACHINE)-windres.exe)
    WINDRES = $(MINGW_HOME)/bin/$(MACHINE)-windres.exe
endif
endif

ifdef PACKAGECODE
    DEFINE_PACKAGECODE = define PACKAGECODE "$(strip $(PACKAGECODE))"
else
    DEFINE_PACKAGECODE = undef PACKAGECODE
endif

$(cygwin.target.dir)/$(TARGET_BASENAME).exe: cleansweep.c $(cygwin.target.dir)/config.h $(cygwin.target.dir)/cleansweep.res
    $(CC) $(CPPFLAGS) cleansweep.c $(target.dir)/cleansweep.res $(LDFLAGS) -o $(target.dir)/$(TARGET_BASENAME).exe $(LIBS)
    -$(MINGW_HOME)/$(MACHINE)/bin/strip.exe $(target.dir)/$(TARGET_BASENAME).exe

.PHONY: $(cygwin.target.dir)/config.h

$(cygwin.target.dir)/config.h:
    -rm.exe -f ../../../../../resources/install/windows/config.h
    echo #define PRODUCTNAME "$(PRODUCTNAME)" > $(cygwin.target.dir)/config.h
    echo #$(DEFINE_PACKAGECODE) >> $(cygwin.target.dir)/config.h

$(cygwin.target.dir)/cleansweep.res: cleansweep.rc $(cygwin.target.dir)/config.h
    $(WINDRES) -I../../../../../resources/install/windows -I$(target.dir) cleansweep.rc -O coff -o $(target.dir)/cleansweep.res

Change Default Revision Number

Building the installer will fail with an ambiguous error if the default 0.build.by.SVN revision is not changed.  This can be done at the bottom of  .\src\net\java\sip\communicator\impl\version\NightlyBuildID.java.  It should be a whole number such as 1 or 222 etc.  

Alternatively, the revision number can be changed in Eclipse.  This will override the value in the above file.  From the top menu goto Run > External Tools > External Tools Configuration > Ant Build > Jitsi build.xml > Main

Arguments:-Dlabel= 222

If you have multiple arguments add one per line.

Build Windows Installer

To build the installer go to the Ant section in the middle right hand side of the Eclipse workspace and select build-installation-wix for 32bit and build-installation-wix-64 for the 64bit version.  The app will be saved in .\release\windows when done.  

There will be some errors (ie. cannot find config.h) which are normal.  As long as the build completes the errors can probably be ignored.  There should be plenty of details in the console for troublshooting problems.  In particular, check all the resolved directory paths shown to make sure they are all correct. 

Any errors building the installer are most likely problems with Windows environment paths or the Makefiles. 

Sections: