Difference between revisions of "Multiplatform Programming Guide"

From Lazarus wiki
Jump to navigationJump to search
Line 11: Line 11:
 
Many Windows programs use the Windows API extensively. On crossplatform applications those functions cannot appear, or must be enclosed by a condition compile ( {$IFDEF Win32} ).
 
Many Windows programs use the Windows API extensively. On crossplatform applications those functions cannot appear, or must be enclosed by a condition compile ( {$IFDEF Win32} ).
  
Happily many Windows API functions, the most used, are implemented on a multiplatform way on the unit LCLIntf. This can be a solution from programs witch rely heavely on the Windows API, althought the best solution is to substitute the calls with true crossplatform components from the LCL. You can substitute calls to GDI painting functions with the TCanvas object, for example.
+
Happily many Windows API functions, the most used, are implemented on a multiplatform way on the unit LCLIntf. This can be a solution from programs which rely heavily on the Windows API, although the best solution is to substitute the calls with true crossplatform components from the LCL. You can substitute calls to GDI painting functions with the TCanvas object, for example.
  
 
===File system differences===
 
===File system differences===

Revision as of 10:56, 4 January 2006

This page is the start of a tutorial with regard to writing multiplatform applications on Lazarus. It will cover both the necessary precautions to ensure that a program can be easely ported and the porting process for an already existing program. I invite others to help improve the article.

Introduction to Multiplatform Programming

Porting process between Windows and Linux

Windows API Functions

Many Windows programs use the Windows API extensively. On crossplatform applications those functions cannot appear, or must be enclosed by a condition compile ( {$IFDEF Win32} ).

Happily many Windows API functions, the most used, are implemented on a multiplatform way on the unit LCLIntf. This can be a solution from programs which rely heavily on the Windows API, although the best solution is to substitute the calls with true crossplatform components from the LCL. You can substitute calls to GDI painting functions with the TCanvas object, for example.

File system differences

A basic concern when porting application between Linux and Windows is the file system. To start with Windows filenames are not case sensitive, while they are on Unix platforms. This can be the cause of annoying bugs, so any portable application should use consistently filenames.

On Linux there is no "application directory"

One concern when porting applications between Linux and Windows is the file system. Many programmers are used to call ExtractFilePath(ParamStr(0)) or Application.ExeName to get the location of the executable, and then search for the necessary files for the program execution (Images, XML files, database files, etc) based on the location of the executable. This is incorrect in Linux. The string on ParamStr(0) may not only not contain the directory of the executable, as it also varies between different shell programs (sh, bash, etc).

Even if Application.ExeName could in fact know the directory where the file under execution is, that file could be a symbolic link, so you would get the directory of the link instead.

So what should we do? On Linux you should use two different places to store configurations and resource files:

  • Resource files (i.e. images, help files)

A fixed privileged location for the executable and resource files witch will not change.

This location can be something like: /usr/share/app_name or /opt/app_name

Most programs will be executed without root privileges and the fixed directory for a given application usually only available for the root user to write, so don't write on this directory. Only read information from it.

  • Configuration files

You can use the GetAppConfigDir function from SysUtils unit to get a suitable place to store configuration files on different system. The function has one parameter, called Global. If it is True then the directory returned is a global directory, i.e. valid for all users on the system. If the parameter Global is false, then the directory is specific for the user who is executing the program. On systems that do not support multi-user environments, these two directories may be the same.

There is also the GetAppConfigFile witch will return an appropriate name for an application configuration file.

Here is an example of the output of those functions on different systems:

program project1;

{$mode objfpc}{$H+}

uses
  SysUtils;

begin
  WriteLn(GetAppConfigDir(True));
  WriteLn(GetAppConfigDir(False));
  WriteLn(GetAppConfigFile(True));
  WriteLn(GetAppConfigFile(False));
end.

The output on a GNU/Linux system:

/etc
/home/felipe/project1
/etc/project1.cfg
/home/felipe/.project1

You can notice that glocal configuration files are stored on the /etc directory and local configurations are stored on a hidden folder on the user's home directory. Directories whose name begin with a dot (.) are hidden on Linux. You can create a directory on the location returned by GetAppConfigDir and then store configuration files there.

The output on Windows XP:

C:\Programas\teste
C:\Documents and Settings\felipe\Configurações Locais\Dados de aplicativos\project2
C:\Programas\teste\project2.cfg
C:\Documents and Settings\felipe\Configurações Locais\Dados de aplicativos\project2\project2.cfg

Notice that the function uses the directory where the application is to store global configurations on Windows.

Note: The use of UPX interferes with the use of the GetAppConfigDir and GetAppConfigFile functions.

See Also