= Legacy applications = A '''legacy application''' is one which is difficult to modify to use the BOINC API (for example, because an executable is available, but not the source code). Such applications can be run under BOINC using a 'wrapper application' supplied by BOINC. The wrapper handles all communication with the core client, and runs the legacy application as a subprocess: [[Image(http://boinc.berkeley.edu/wrapper.png)]] The wrapper program (called 'wrapper') is in [ExampleApps boinc_samples]. It reads a file called 'job.xml' with format: {{{ worker_5.10_windows_intelx86.exe [ stdin_file ] [ stdout_file ] [ stderr_file ] [ --foo bar ] [ ... ] }}} The job file specifies a sequence of tasks. The job file can specify multiple tasks. This is useful for two purposes: * To handle jobs that involve multiple steps (e.g., preprocessing and postprocessing). * To break a long job up into smaller pieces. This provides a form of checkpointing: ''wrapper'' does checkpointing at the task level, so that lost CPU time can be limited even if the legacy applications themselves are not restartable. Notes: * This requires version 5.5 or higher of the BOINC core client. * Files opened directly by a worker program must have the tag. * If '''wrapper''' is passed command-line arguments (e.g., specified in the workunit template) these are passed to each of the applications, after those specified in the job file. * If the wrapper is used in standalone mode (while debugging), you have to provide the input files with the proper logical, not physical, names. == Example == Here's an example that shows how to set this up: * Compile the program 'worker' from the [ExampleApps boinc_samples] tree, producing (say) 'worker_5.10_windows_intelx86.exe'. This is the legacy app. If reads from stdin and writes to stdout; it also opens and reads a file 'in', and opens and writes a file 'out'. It takes one command-line argument: the number of CPU seconds to use. * Compile the program 'wrapper' from the [ExampleApps boinc_samples] tree, producing (say) 'wrapper_5.10_windows_intelx86.exe'. This program executes your legacy application, and acts as a proxy for it (to report CPU time etc.). * [AppVersion Create an application] named 'worker', and a corresponding directory 'project/apps/worker'. In this directory, create a directory 'wrapper_5.10_windows_intelx86.exe'. Put the files 'wrapper_5.10_windows_intelx86.exe', and 'worker_5.10_windows_intelx86.exe' there. * In the same directory, create a file 'job.xml=job_1.12.xml' (1.12 is a version number) containing {{{ worker_5.10_windows_intelx86.exe stdin stdout 10 }}} This file is read by 'wrapper'; it tells it the name of the legacy program, what files to connect to its stdin/stdout, and a command line. * Create a workunit template file {{{ 0 1 0 in 1 stdin 1000000000000 1000000000000 }}} and a result template file {{{ 5000000 5000000 out stdout }}} * Run [UpdateVersions update_versions] to create an app version. * Run a script like {{{ cp download/input `bin/dir_hier_path input` cp download/input2 `bin/dir_hier_path input2` bin/create_work -appname worker -wu_name worker_nodelete \ -wu_template templates/worker_wu \ -result_template templates/worker_result \ input input2 }}} to generate a workunit. To understand how all this works: at the beginning of execution, the file layout is: ||'''Project directory'''||'''slot directory'''|| ||input||in (copy of project/input)|| ||job_1.12.xml||job.xml (link to project/job_1.12.xml)|| ||input2||stdin (link to project/input2)|| ||worker_nodelete_0||stdout (link to project/worker_nodelete_0)|| ||worker_5.10_windows_intelx86.exe||worker_5.10_windows_intelx86.exe (link to project/worker_5.10_windows_intelx86.exe) ||wrapper_5.10_windows_intelx86.exe||wrapper_5.10_windows_intelx86.exe(link to project/wrapper_5.10_windows_intelx86.exe) || The wrapper program executes the worker, connecting its stdin to project/input2 and its stdout to project/worker_nodelete_0. The worker program opens 'in' for reading and 'out' for writing. When the worker program finishes, the wrapper sees this and exits. Then the BOINC core client copies slot/out to project/worker_nodelete_1.