InstantFPC: what changed
Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.
| Old | New | Line | |
|---|---|---|---|
| 1 | 1 | # Overview | |
| 2 | 2 | ||
| 3 | 3 | This tool allows to run pascal programs as scripts under Linux, BSD, macOS and Windows. For example: | |
| 4 | 4 | ||
| 5 | 5 | ``` pascal | |
| 6 | 6 | #!/usr/bin/env instantfpc | |
| 7 | 7 | begin | |
| 8 | 8 | writeln('Hello fpc user'); | |
| 9 | 9 | end. | |
| 10 | 10 | ``` | |
| 11 | 11 | ||
| 12 | 12 | Save the file as hello.pas, set the permission to execute and run it: | |
| 13 | 13 | ||
| 14 | 14 | ``` bash | |
| 15 | 15 | chmod a+x hello.pas | |
| 16 | 16 | ./hello.pas | |
| 17 | 17 | Hello fpc user | |
| 18 | 18 | ``` | |
| 19 | 19 | ||
| 20 | 20 | **Notes:** | |
| 21 | 21 | ||
| 22 | 22 | - The first line is called *shebang* and is stripped from the source before passing it to the compiler. | |
| 23 | 23 | - The line 'program hello;' is optional in FPC. Because **instantfpc** passes the **-o** option to the compiler the line is ignored, so you can omit it. | |
| 24 | 24 | ||
| 25 | 25 | Of course you can pass parameters to your script: | |
| 26 | 26 | ||
| 27 | 27 | ``` pascal | |
| 28 | 28 | #!/usr/bin/env instantfpc | |
| 29 | 29 | var | |
| 30 | 30 | i: Integer; | |
| 31 | 31 | begin | |
| 32 | 32 | for i:=0 to ParamCount do writeln(ParamStr(i)); | |
| 33 | 33 | end. | |
| 34 | 34 | ``` | |
| 35 | 35 | ||
| 36 | 36 | Save the file as params.pas, set the permission to execute and run it: | |
| 37 | 37 | ||
| 38 | 38 | ``` bash | |
| 39 | 39 | chmod a+x params.pas | |
| 40 | 40 | ./params.pas A B | |
| 41 | 41 | ``` | |
| 42 | 42 | ||
| 43 | 43 | It gives output like: | |
| 44 | 44 | ||
| 45 | 45 | /home/username/.cache/instantfpc/params.pas | |
| 46 | 46 | A | |
| 47 | 47 | B | |
| 48 | 48 | ||
| 49 | 49 | # Download | |
| 50 | 50 | ||
| 51 | 51 | No need to download: instantfpc is part of the FPC 2.6+ sources under *utils/instantfpc* and installed by default. | |
| 52 | 52 | ||
| 53 | 53 | ## Old versions | |
| 54 | 54 | ||
| 55 | 55 | For fpc 2.5.1 and above: It is in the fpc sources: | |
| 56 | 56 | ||
| 57 | 57 | ``` bash | |
| 58 | 58 | svn co http://svn.freepascal.org/svn/fpc/trunk/utils/instantfpc instantfpc | |
| 59 | 59 | ``` | |
| 60 | 60 | ||
| 61 | 61 | For fpc 2.4.4 and 2.4.5: | |
| 62 | 62 | ||
| 63 | 63 | ``` bash | |
| 64 | 64 | svn co https://lazarus-ccr.svn.sourceforge.net/svnroot/lazarus-ccr/applications/instantfpc instantfpc | |
| 65 | 65 | ``` | |
| 66 | 66 | ||
| 67 | 67 | # Installation | |
| 68 | 68 | ||
| 69 | 69 | Note: It is already installed when using fpc 2.5.1 and above. Windows users have to put the instantfpc.exe into a directory of their PATH. | |
| 70 | 70 | ||
| 71 | 71 | 1. Compile the instantfpc.lpi with Lazarus or lazbuild. Or compile directly with *fpc instantfpc.pas*. | |
| 72 | 72 | 2. Put the executable into PATH, for example /usr/bin: | |
| 73 | 73 | ||
| 74 | 74 | ``` bash | |
| 75 | 75 | sudo cp instantfpc /usr/bin/ | |
| 76 | 76 | ``` | |
| 77 | 77 | ||
| 78 | 78 | # How it works | |
| 79 | 79 | ||
| 80 | 80 | It uses a cache directory to compile. Default is \$HOME/.cache/instantfpc. If HOME is not set it gives an error. You can override the directory by setting the environment variable INSTANTFPCCACHE. It compares the source with the stored file in cache and if it differs compiles the source, given the parameters in the shebang line (the first line of the script after \#!). After successful compile it executes the program. If compilation fails it writes the fpc output to stdout. | |
| 81 | 81 | ||
| 82 | 82 | # Parameters for instantfpc | |
| 83 | 83 | ||
| 84 | 84 | - **-h**: Print help and exit | |
| 85 | 85 | - **-v**: Print current version and exit | |
| 86 | 86 | - **--get-cache**: Print current cache directory and exit | |
| 87 | 87 | - **--set-cache=\<directory\>**: Set cache directory | |
| 88 | 88 | - **-B**: always compile even if cache is valid. | |
| 89 | 89 | - **--compiler=\<path to compiler\>** use this compiler. By default fpc is searched in PATH. | |
| 90 | 90 | - **--skip-run**: Do not execute the program. Useful to test if script compiles. Best combined with -B. | |
| 91 | 91 | - **--**: Read the program source from standard input. Note that the compiled program has no input then. | |
| 92 | 92 | - Environment variable **INSTANTFPCCACHE**: Set cache directory. The --get-cache can override this. | |
| 93 | 93 | - Environment variable **INSTANTFPCOPTIONS**: Options to pass to the compiler. Passed before the command line parameters. | |
| 94 | 94 | ||
| 95 | 95 | # Passing parameters to the compiler | |
| 96 | 96 | ||
| 97 | 97 | Compiler parameters can be passed in the shebang line. Note: You can not use the 'env' command. | |
| 98 | 98 | ||
| 99 | 99 | ``` pascal | |
| 100 | 100 | #!/usr/bin/instantfpc -O1 -Ci | |
| 101 | 101 | begin | |
| 102 | 102 | end. | |
| 103 | 103 | ``` | |
| 104 | 104 | ||
| 105 | 105 | And/Or you can put compiler options in the environment variable **INSTANTFPCOPTIONS**: | |
| 106 | 106 | ||
| 107 | 107 | ``` bash | |
| 108 | 108 | export INSTANTFPCOPTIONS="-Fu~/lazarus/components/codetools/units/x86_64-linux/" | |
| 109 | 109 | ``` | |
| 110 | 110 | ||
| 111 | 111 | ``` pascal | |
| 112 | 112 | #!/usr/bin/instantfpc | |
| 113 | 113 | uses FileProcs; // unit FileProcs is in codetools | |
| 114 | 114 | begin | |
| 115 | 115 | end. | |
| 116 | 116 | ``` | |
| 117 | 117 | ||
| 118 | 118 | # Example | |
| 119 | 119 | ||
| 120 | 120 | The following example script delivers the (unintelligible!) numeronym of a string (e.g. i18n for internationalization) that may be provided either as a parameter or, if missing, be entered by the user: | |
| 121 | 121 | ||
| 122 | 122 | ``` pascal | |
| 123 | 123 | #!/usr/bin/env instantfpc | |
| 124 | 124 | uses | |
| 125 | 125 | SysUtils; | |
| 126 | 126 | var | |
| 127 | 127 | theWord: String; | |
| 128 | 128 | begin | |
| 129 | 129 | if ParamStr(1) = '' then | |
| 130 | 130 | begin | |
| 131 | 131 | write('Please enter the word to be numeronymized: '); | |
| 132 | 132 | readln(theWord); | |
| 133 | 133 | end | |
| 134 | 134 | else | |
| 135 | 135 | theWord := ParamStr(1); | |
| 136 | 136 | if length(theWord) > 2 then | |
| 137 | 137 | writeln(theWord[1] + IntToStr(length(theWord)-2) + theWord[length(theWord)]) | |
| 138 | 138 | else | |
| 139 | 139 | writeln('N/A'); | |
| 140 | 140 | end. | |
| 141 | 141 | ``` | |
| 142 | 142 | ||
| 143 | 143 | The following shows how you don't even need to have a source file to use instantfpc: | |
| 144 | 144 | ||
| 145 | 145 | ``` pascal | |
| 146 | 146 | echo "begin writeln('hello, world!') end." | ./instantfpc -- | |
| 147 | 147 | ``` | |
| 148 | 148 | ||
| 149 | 149 | # Using with Lazarus | |
| 150 | 150 | ||
| 151 | 151 | Since Lazarus 0.9.31 the IDE ignores the shebang line. You get all the normal code features. | |
| 152 | 152 | ||
| 153 | 153 | Install the IDE package **instantfpclaz**, which comes with Lazarus. This will add a new project item to create instantfpc programs, for example under File / New / Project / InstantFPC program. | |
| 154 | 154 | ||
| 155 | 155 | ## Compile in Lazarus | |
| 156 | 156 | ||
| 157 | 157 | How to convert a Lazarus project to compile it with **instantfpc**: | |
| 158 | 158 | ||
| 159 | 159 | Requires: | |
| 160 | 160 | ||
| 161 | 161 | - Lazarus project main source file is the instantfpc program | |
| 162 | 162 | ||
| 163 | 163 | Setup: | |
| 164 | 164 | ||
| 165 | 165 | - Go to Project Options / Compiler Options / Compilation | |
| 166 | 166 | - Disable all **Call on** checks for **Compiler** | |
| 167 | 167 | - Set in **Execute before** the **Command** to: | |
| 168 | 168 | ||
| 169 | 169 | ``` bash | |
| 170 | 170 | instantfpc --skip-run -B -gl "-Fu$(ProjUnitPath)" $Name($(ProjFile)) | |
| 171 | 171 | ``` | |
| 172 | 172 | ||
| 173 | 173 | - Enable checkboxes to scan *make* and *fpc* | |
| 174 | 174 | ||
| 175 | 175 | Notes: | |
| 176 | 176 | ||
| 177 | 177 | - The *-gl* will tell FPC to compile with debugging information | |
| 178 | 178 | - The *--skip-run -B* compiles without executing | |
| 179 | 179 | - See [[IDE Macros in paths and filenames|IDE Macros]] | |
| 180 | 180 | ||
| 181 | 181 | ## Debug with Lazarus | |
| 182 | 182 | ||
| 183 | 183 | How to convert a Lazarus project to debug an instantfpc program: | |
| 184 | 184 | ||
| 185 | 185 | Requires: | |
| 186 | 186 | ||
| 187 | 187 | - The above **Compile in Lazarus** | |
| 188 | 188 | ||
| 189 | 189 | Setup: | |
| 190 | 190 | ||
| 191 | 191 | - Go to Run / Run parameters | |
| 192 | 192 | - Set **Local / Host application** to | |
| 193 | 193 | ||
| 194 | - | ||
| 194 | + | ```text | |
| 195 | + | $(InstantFPCCache)/$NameOnly($(ProjFile)) | |
| 196 | + | ``` | |
| 195 | 197 | ||
| 196 | 198 | - Set **Working Directory** to | |
| 197 | 199 | ||
| 198 | - | ||
| 200 | + | ```text | |
| 201 | + | $(ProjPath) | |
| 202 | + | ``` | |
| 199 | 203 | ||
| 200 | 204 | ## Use as Pascal script without an .lpi file | |
| 201 | 205 | ||
| 202 | 206 | Open the script in the source editor. Then click in menu **Run / Configure Build and Run**. | |
| 203 | 207 | ||
| 204 | 208 | - Page **Options**: | |
| 205 | 209 | - **On build project execute the Build File command instead**: Enable this if you like to compile the script on Ctrl+F9. | |
| 206 | 210 | - **On run project execute the Run File command instead**: Enable this if you like to execute the script on F9. Note: **instantfpc** automatically compiles if the file has changed. | |
| 207 | 211 | - Page **Build**: | |
| 208 | 212 | - *'Build Command*: /path/to/instantfpc --skip-run -B -gl \$(EdFile) | |
| 209 | 213 | - **Scan for FPC messages**: enable | |
| 210 | 214 | - Page **Run**: | |
| 211 | 215 | - *'Build Command*: /path/to/instantfpc -gl \$(EdFile) | |
| 212 | 216 | ||
| 213 | 217 | Click Ok. You should see something like this: | |
| 214 | 218 | ||
| 215 | 219 | ``` pascal | |
| 216 | 220 | #!/usr/bin/instantfpc | |
| 217 | 221 | {%BuildCommand /path/to/instantfpc --skip-run -B -gl $(EdFile)} | |
| 218 | 222 | {%RunCommand /path/to/instantfpc -gl $(EdFile)} | |
| 219 | 223 | begin | |
| 220 | 224 | end. | |
| 221 | 225 | ``` | |
| 222 | 226 | ||
| 223 | 227 | # Using in Apache | |
| 224 | 228 | ||
| 225 | 229 | This is how to use instantfpc in Apache Webserver. Instantfpc needs the cache directory, which must be writable by the account of Apache. Let's say Apache is running under user www-data, group www-data (Redhat, Fedora: apache.apache, see apache config for User and Group). | |
| 226 | 230 | ||
| 227 | 231 | ``` bash | |
| 228 | 232 | mkdir /var/apacheinstantfpc | |
| 229 | 233 | chown www-data.www-data /var/apacheinstantfpc | |
| 230 | 234 | ``` | |
| 231 | 235 | ||
| 232 | 236 | Pass an environment variable to cgi scripts by adding the following line to the Apache configs: | |
| 233 | 237 | ||
| 234 | - | ||
| 238 | + | ``` pascal | |
| 239 | + | SetEnv INSTANTFPCCACHE /var/apacheinstantfpc | |
| 240 | + | ``` | |
| 235 | 241 | ||
| 236 | 242 | **Security advice:** Although the apache user must have full access to the cache directory, make sure the directory is not available from outside (e.g. do not put it under /var/www). It may contain old scripts. And like any other type of scripts: Check all input for attacks. | |
| 237 | 243 | ||
| 238 | 244 | **Optimization note:** The instantfpc cache uses one file per script name. **Do not use the same script name twice**, otherwise it will be compiled many times. You can create multiple cache directories. Each \<directory\> and \<virtualhost\> section can define their own environment variables, and therefore you can setup one cache directory for each. | |
| 239 | 245 | ||
| 240 | 246 | ## Apache example showing env | |
| 241 | 247 | ||
| 242 | 248 | Configure a directory to execute cgi scripts. For example: | |
| 243 | 249 | ||
| 244 | - | ||
| 245 | - | ||
| 246 | - | ||
| 247 | - | ||
| 248 | - | ||
| 249 | - | ||
| 250 | - | ||
| 251 | - | ||
| 252 | - | ||
| 253 | - | ||
| 254 | - | ||
| 255 | - | ||
| 250 | + | ``` pascal | |
| 251 | + | ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ | |
| 252 | + | <Directory "/usr/lib/cgi-bin"> | |
| 253 | + | AllowOverride None | |
| 254 | + | Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch | |
| 255 | + | Order allow,deny | |
| 256 | + | Allow from all | |
| 257 | + | SetEnv INSTANTFPCCACHE /var/apacheinstantfpc | |
| 258 | + | # You can put fpc options into /etc/fpc.cfg or here: | |
| 259 | + | #SetEnv INSTANTFPCOPTIONS -Fu/path/to/somevar/ppufiles | |
| 260 | + | # If this is root directory, you might have to set: | |
| 261 | + | #Require all granted | |
| 262 | + | </Directory> | |
| 263 | + | ``` | |
| 256 | 264 | ||
| 257 | 265 | If your apache has not yet enabled the **cgi** module: | |
| 258 | 266 | ||
| 259 | - | ||
| 267 | + | ```text | |
| 268 | + | a2enmod cgi | |
| 269 | + | ``` | |
| 260 | 270 | ||
| 261 | 271 | Put the following script into /usr/lib/cgi-bin/showenv.pas: | |
| 262 | 272 | ||
| 263 | 273 | ``` pascal | |
| 264 | 274 | #!/usr/bin/instantfpc | |
| 265 | 275 | {$mode objfpc}{$H+} | |
| 266 | 276 | uses SysUtils; | |
| 267 | 277 | var i: Integer; | |
| 268 | 278 | begin | |
| 269 | 279 | writeln('Content-type: text/html'); | |
| 270 | 280 | writeln; | |
| 271 | 281 | writeln('<HTML><BODY>'); | |
| 272 | 282 | for i:=0 to Paramcount do | |
| 273 | 283 | writeln('Param ',i,' ',ParamStr(i),'<br>'); | |
| 274 | 284 | for i:=1 to GetEnvironmentVariableCount do | |
| 275 | 285 | writeln('Env ',GetEnvironmentString(i),'<br>'); | |
| 276 | 286 | writeln('</BODY></HTML>'); | |
| 277 | 287 | end. | |
| 278 | 288 | ``` | |
| 279 | 289 | ||
| 280 | 290 | # Bugs / ToDos / Limitations | |
| 281 | 291 | ||
| 282 | 292 | - Changes to the compiler or installed units are not checked. If you install a new compiler you should clean the cache (e.g. delete the directory ~/.cache/instantfpc). | |
| 283 | 293 | - Under Windows only the first parameter is passed to the script. | |
| 284 | 294 | - With instantfpc versions less than 1.3 you can not compile in parallel. The compiler creates hidden files like 'link.res' while compiling. Since 1.3 instantfpc uses temporary directories for compiling. | |
| 285 | 295 | - The cache uses the file name without the path. So you cannot execute two scripts in parallel of the same name. Every run time the script will be compiled. | |
| 286 | 296 | ||
| 287 | 297 | # Alternatives | |
| 288 | 298 | ||
| 289 | 299 | The following trick works using the *bash* shell. Put the program into a file *fpc_script.sh*: | |
| 290 | 300 | ||
| 291 | 301 | ``` pascal | |
| 292 | 302 | // 2>/dev/null; fpc fpc_script.pp &> build.log && exec ./fpc_script "$@" || cat build.log; exit | |
| 293 | 303 | begin | |
| 294 | 304 | writeln(' no one knows how this is a trick or offers any advantage at all '); | |
| 295 | 305 | end. | |
| 296 | 306 | ``` | |
| 297 | 307 | ||
| 298 | 308 | --- | |
| 299 | 309 | *From the Free Pascal wiki, page "InstantFPC", as it stood on 2022-03-18 after a change by Kai Burghardt, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).* |
