summaryrefslogtreecommitdiff
path: root/DEVELOPING.md
blob: df76323c8d3c47ba0bbdb0c182d7b91e6fa95374 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
Developing for CUPS
===================

Please see the [Contributing to CUPS](CONTRIBUTING.md) file for information on
contributing to the CUPS project.


How To Contact The Developers
-----------------------------

The CUPS mailing lists are the primary means of asking questions and informally
discussing issues and feature requests with the CUPS developers and other
experienced CUPS users and developers.  The "cups" mailing list is intended for
CUPS usage questions and new software announcements while the "cups-devel"
mailing list provides a forum for CUPS developers and monitoring new bugs.


Interfaces
----------

CUPS interfaces, including the C APIs and command-line arguments, environment
variables, configuration files, and output format, are stable across patch
versions and are generally backwards-compatible with interfaces used in prior
major and minor versions.  However, program interfaces such as those used by
the scheduler to run filter, port monitor, and backend processes for job
processing should only be considered stable from the point of view of a
filter, port monitor, or backend.  Software that simulates the scheduler in
order to run those programs outside of CUPS must necessarily be updated when
the corresponding interface is changed in a subsequent CUPS release, otherwise
undefined behavior can occur.

CUPS C APIs starting with an underscore (`_`) are considered to be private to
CUPS and are not subject to the normal guarantees of stability between CUPS
releases and must never be used in non-CUPS source code.  Similarly,
configuration and state files written by CUPS are considered private if a
corresponding man page is not provided with the CUPS release.  Never rely on
undocumented files or formats when developing software for CUPS.  Always use a
published C API to access data stored in a file to avoid compatibility problems
in the future.


Build System
------------

The CUPS build system uses GNU autoconf to tailor the library to the local
operating system.  Project files for the current release of Microsoft Visual
Studio are also provided for Microsoft Windows®.  To improve portability,
makefiles must not make use of features unique to GNU make.  See the MAKEFILE
GUIDELINES section for a description of the allowed make features and makefile
guidelines.

Additional GNU build programs such as GNU automake and GNU libtool must not be
used.  GNU automake produces non-portable makefiles which depend on GNU-
specific extensions, and GNU libtool is not portable or reliable enough for
CUPS.


Version Numbering
-----------------

CUPS uses a three-part version number separated by periods to represent the
major, minor, and patch release numbers.  Major release numbers indicate large
design changes or backwards-incompatible changes to the CUPS API or CUPS
Imaging API.  Minor release numbers indicate new features and other smaller
changes which are backwards-compatible with previous CUPS releases.  Patch
numbers indicate bug fixes to the previous feature or patch release.  This
version numbering scheme is consistent with the
[Semantic Versioning](http://semver.org) specification.

> Note:
>
> When we talk about compatibility, we are talking about binary compatibility
> for public APIs and output format compatibility for program interfaces.
> Changes to configuration file formats or the default behavior of programs
> are not generally considered incompatible as the upgrade process can
> normally address such changes gracefully.

Production releases use the plain version numbers:

    MAJOR.MINOR.PATCH
    1.0.0
    ...
    1.1.0
    ...
    1.1.23
    ...
    2.0.0
    ...
    2.1.0
    2.1.1
    2.1.2
    2.1.3

The first production release in a MAJOR.MINOR series (MAJOR.MINOR.0) is called
a feature release.  Feature releases are the only releases that may contain new
features.  Subsequent production releases in a MAJOR.MINOR series may only
contain bug fixes.

Beta-test releases are identified by appending the letter B to the major and
minor version numbers followed by the beta release number:

    MAJOR.MINORbNUMBER
    2.2b1

Release candidates are identified by appending the letters RC to the major and
minor version numbers followed by the release candidate number:

    MAJOR.MINORrcNUMBER
    2.2rc1


Coding Guidelines
-----------------

Contributed source code must follow the guidelines below.  While the examples
are for C and C++ source files, source code for other languages should conform
to the same guidelines as allowed by the language.

Source code comments provide the reference portion of the CUPS Programming
Manual, which is generated using the [codedoc](https://www.msweet.org/codedoc)
software.


### Source Files

All source files names must be 16 characters or less in length to ensure
compatibility with older UNIX filesystems.  Source files containing functions
have an extension of ".c" for C and ".cxx" for C++ source files.  All other
"include" files have an extension of ".h".  Tabs are set to 8 characters or
columns.

> Note:
>
> The ".cxx" extension is used because it is the only common C++ extension
> between Linux, macOS, UNIX, and Windows.

The top of each source file contains a header giving the purpose or nature of
the source file and the copyright and licensing notice:

    /*
     * Description of file contents.
     *
     * Copyright 2017 by Apple Inc.
     *
     * Licensed under Apache License v2.0.  See the file "LICENSE" for more
     * information.
     */


### Header Files

All public header files must include the "versioning.h" header file, or a header
that does so.  Function declarations are then "decorated" with the correct
`_CUPS_API_major_minor` macro to define its availability based on the build
environment, for example:

    extern int cupsDoThis(int foo, int bar) _CUPS_API_2_2;

Private API header files must be named with the suffix "-private", for example
the "cups.h" header file defines all of the public CUPS APIs while the
"cups-private.h" header file defines all of the private CUPS APIs as well.
Typically a private API header file will include the corresponding public API
header file.


### Comments

All source code utilizes block comments within functions to describe the
operations being performed by a group of statements; avoid putting a comment
per line unless absolutely necessary, and then consider refactoring the code
so that it is not necessary.  C source files use the block comment format
("/* comment */") since many vendor C compilers still do not support C99/C++
comments ("// comment"):

    /*
     * Clear the state array before we begin...
     */

     for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
       array[i] = CUPS_STATE_IDLE;

    /*
     * Wait for state changes on another thread...
     */

     do
     {
       for (i = 0; i < (sizeof(array) / sizeof(sizeof(array[0])); i ++)
         if (array[i] != CUPS_STATE_IDLE)
           break;

       if (i == (sizeof(array) / sizeof(array[0])))
         sleep(1);
     } while (i == (sizeof(array) / sizeof(array[0])));


### Indentation

All code blocks enclosed by brackets begin with the opening brace on a new
line.  The code then follows starting on a new line after the brace and is
indented 2 spaces.  The closing brace is then placed on a new line following
the code at the original indentation:

    {
      int i; /* Looping var */

     /*
      * Process foobar values from 0 to 999...
      */

      for (i = 0; i < 1000; i ++)
      {
        do_this(i);
        do_that(i);
      }
    }

Single-line statements following "do", "else", "for", "if", and "while" are
indented 2 spaces as well.  Blocks of code in a "switch" block are indented 4
spaces after each "case" and "default" case:

    switch (array[i])
    {
      case CUPS_STATE_IDLE :
          do_this(i);
          do_that(i);
          break;

      default :
          do_nothing(i);
          break;
    }


### Spacing

A space follows each reserved word such as `if`, `while`, etc.  Spaces are not
inserted between a function name and the arguments in parenthesis.


### Return Values

Parenthesis surround values returned from a function:

    return (CUPS_STATE_IDLE);


### Functions

Functions with a global scope have a lowercase prefix followed by capitalized
words, e.g., `cupsDoThis`, `cupsDoThat`, `cupsDoSomethingElse`, etc.  Private
global functions begin with a leading underscore, e.g., `_cupsDoThis`,
`_cupsDoThat`, etc.

Functions with a local scope are declared static with lowercase names and
underscores between words, e.g., `do_this`, `do_that`, `do_something_else`, etc.

Each function begins with a comment header describing what the function does,
the possible input limits (if any), the possible output values (if any), and
any special information needed:

    /*
     * 'do_this()' - Compute y = this(x).
     *
     * Notes: none.
     */

    static float       /* O - Inverse power value, 0.0 <= y <= 1.1 */
    do_this(float x)   /* I - Power value (0.0 <= x <= 1.1) */
    {
      ...
      return (y);
    }

Return/output values are indicated using an "O" prefix, input values are
indicated using the "I" prefix, and values that are both input and output use
the "IO" prefix for the corresponding in-line comment.

The [codedoc](https://www.msweet.org/codedoc) documentation generator also
understands the following special text in the function description comment:

    @deprecated@         - Marks the function as deprecated: not recommended
                           for new development and scheduled for removal.
    @link name@          - Provides a hyperlink to the corresponding function
                           or type definition.
    @since CUPS version@ - Marks the function as new in the specified version
                           of CUPS.
    @private@            - Marks the function as private so it will not be
                           included in the documentation.


### Variables

Variables with a global scope are capitalized, e.g., `ThisVariable`,
`ThatVariable`, `ThisStateVariable`, etc.  Globals in CUPS libraries are either
part of the per-thread global values managed by the `_cupsGlobals` function
or are suitably protected for concurrent access.  Global variables should be
replaced by function arguments whenever possible.

Variables with a local scope are lowercase with underscores between words,
e.g., `this_variable`, `that_variable`, etc.  Any "local global" variables
shared by functions within a source file are declared static.  As for global
variables, local static variables are suitably protected for concurrent access.

Each variable is declared on a separate line and is immediately followed by a
comment block describing the variable:

    int         ThisVariable;    /* The current state of this */
    static int  that_variable;   /* The current state of that */


### Types

All type names are lowercase with underscores between words and `_t` appended
to the end of the name, e.g., `cups_this_type_t`, `cups_that_type_t`, etc.
Type names start with a prefix, typically `cups` or the name of the program,
to avoid conflicts with system types.  Private type names start with an
underscore, e.g., `_cups_this_t`, `_cups_that_t`, etc.

Each type has a comment block immediately after the typedef:

    typedef int cups_this_type_t;  /* This type is for CUPS foobar options. */


### Structures

All structure names are lowercase with underscores between words and `_s`
appended to the end of the name, e.g., `cups_this_s`, `cups_that_s`, etc.
Structure names start with a prefix, typically `cups` or the name of the
program, to avoid conflicts with system types.  Private structure names start
with an underscore, e.g., `_cups_this_s`, `_cups_that_s`, etc.

Each structure has a comment block immediately after the struct and each member
is documented similar to the variable naming policy above:

    struct cups_this_struct_s  /* This structure is for CUPS foobar options. */
    {
      int this_member;         /* Current state for this */
      int that_member;         /* Current state for that */
    };


### Constants

All constant names are uppercase with underscores between words, e.g.,
`CUPS_THIS_CONSTANT`, `CUPS_THAT_CONSTANT`, etc.  Constants begin with an
uppercase prefix, typically `CUPS_` or the program or type name.  Private
constants start with an underscore, e.g., `_CUPS_THIS_CONSTANT`,
`_CUPS_THAT_CONSTANT`, etc.

Typed enumerations should be used whenever possible to allow for type checking
by the compiler.

Comment blocks immediately follow each constant:

    typedef enum cups_tray_e  /* Tray enumerations */
    {
      CUPS_TRAY_THIS,         /* This tray */
      CUPS_TRAY_THAT          /* That tray */
    } cups_tray_t;


## Makefile Guidelines

The following is a guide to the makefile-based build system used by CUPS.
These standards have been developed over the years to allow CUPS to be built on
as many systems and environments as possible.


### General Organization

The CUPS source code is organized functionally into a top-level makefile,
include file, and subdirectories each with their own makefile and dependencies
files.  The ".in" files are template files for the autoconf software and are
used to generate a static version of the corresponding file.


### Makefile Documentation

Each makefile starts with the standard CUPS header containing the description
of the file, and CUPS copyright and license notice:

    #
    # Makefile for ...
    #
    # Copyright 2017 by Apple Inc.
    #
    # Licensed under Apache License v2.0.  See the file "LICENSE" for more
    # information.
    #


### Portable Makefile Construction

CUPS uses a common subset of make program syntax to ensure that the software
can be compiled "out of the box" on as many systems as possible.  The following
is a list of assumptions we follow when constructing makefiles:

- Targets; we assume that the make program supports the notion of simple
  targets of the form "name:" that perform tab-indented commands that follow
  the target, e.g.:

      target:
      TAB target commands

- Dependencies; we assume that the make program supports recursive dependencies
  on targets, e.g.:

      target: foo bar
      TAB target commands

      foo: bla
      TAB foo commands

      bar:
      TAB bar commands

      bla:
      TAB bla commands

- Variable Definition; we assume that the make program supports variable
  definition on the command-line or in the makefile using the following form:

      name=value

- Variable Substitution; we assume that the make program supports variable
  substitution using the following forms:

      - `$(name)`; substitutes the value of "name",
      - `$(name:.old=.new)`; substitutes the value of "name" with the filename
        extension ".old" changed to ".new",
      - `$(MAKEFLAGS)`; substitutes the command-line options passed to the
        program without the leading hyphen (-),
      - `$$`; substitutes a single $ character,
      - `$<`; substitutes the current source file or dependency, and
      - `$@`; substitutes the current target name.

- Suffixes; we assume that the make program supports filename suffixes with
  assumed dependencies, e.g.:

      .SUFFIXES: .c .o
      .c.o:
      TAB $(CC) $(CFLAGS) -o $@ -c $<

- Include Files; we assume that the make program supports the include
  directive, e.g.:

      include ../Makedefs
      include Dependencies

- Comments; we assume that comments begin with a # character and proceed to the
  end of the current line.

- Line Length; we assume that there is no practical limit to the length of
  lines.

- Continuation of long lines; we assume that the `\` character may be placed at
  the end of a line to concatenate two or more lines in a makefile to form a
  single long line.

- Shell; we assume a POSIX-compatible shell is present on the build system.


### Standard Variables

The following variables are defined in the "Makedefs" file generated by the
autoconf software:

- `ALL_CFLAGS`; the combined C compiler options,
- `ALL_CXXFLAGS`; the combined C++ compiler options,
- `AMANDIR`; the administrative man page installation directory (section 8/1m
  depending on the platform),
- `AR`; the library archiver command,
- `ARFLAGS`; options for the library archiver command,
- `AWK`; the local awk command,
- `BINDIR`; the binary installation directory,
- `BUILDROOT`; optional installation prefix (defaults to DSTROOT),
- `CC`; the C compiler command,
- `CFLAGS`; options for the C compiler command,
- `CHMOD`; the chmod command,
- `CXX`; the C++ compiler command,
- `CXXFLAGS`; options for the C++ compiler command,
- `DATADIR`; the data file installation directory,
- `DSO`; the C shared library building command,
- `DSOXX`; the C++ shared library building command,
- `DSOFLAGS`; options for the shared library building command,
- `INCLUDEDIR`; the public header file installation directory,
- `INSTALL`; the install command,
- `INSTALL_BIN`; the program installation command,
- `INSTALL_COMPDATA`; the compressed data file installation command,
- `INSTALL_CONFIG`; the configuration file installation command,
- `INSTALL_DATA`; the data file installation command,
- `INSTALL_DIR`; the directory installation command,
- `INSTALL_LIB`; the library installation command,
- `INSTALL_MAN`; the documentation installation command,
- `INSTALL_SCRIPT`; the shell script installation command,
- `LD`; the linker command,
- `LDFLAGS`; options for the linker,
- `LIBDIR`; the library installation directory,
- `LIBS`; libraries for all programs,
- `LN`; the ln command,
- `MAN1EXT`; extension for man pages in section 1,
- `MAN3EXT`; extension for man pages in section 3,
- `MAN5EXT`; extension for man pages in section 5,
- `MAN7EXT`; extension for man pages in section 7,
- `MAN8DIR`; subdirectory for man pages in section 8,
- `MAN8EXT`; extension for man pages in section 8,
- `MANDIR`; the man page installation directory,
- `OPTIM`; common compiler optimization options,
- `PRIVATEINCLUDE`; the private header file installation directory,
- `RM`; the rm command,
- `SHELL`; the sh (POSIX shell) command,
- `STRIP`; the strip command,
- `srcdir`; the source directory.


### Standard Targets

The following standard targets are defined in each makefile:

- `all`; creates all target programs, libraries, and documentation files,
- `clean`; removes all target programs libraries, documentation files, and object
  files,
- `depend`; generates automatic dependencies for any C or C++ source files (also
  see "DEPENDENCIES"),
- `distclean`; removes autoconf-generated files in addition to those removed by
  the "clean" target,
- `install`; installs all distribution files in their corresponding locations
  (also see "INSTALL/UNINSTALL SUPPORT"),
- `install-data`; installs all data files in their corresponding locations (also
  see "INSTALL/UNINSTALL SUPPORT"),
- `install-exec`; installs all executable files in their corresponding locations
  (also see "INSTALL/UNINSTALL SUPPORT"),
- `install-headers`; installs all include files in their corresponding locations
  (also see "INSTALL/UNINSTALL SUPPORT"),
- `install-libs`; installs all library files in their corresponding locations
  (also see "INSTALL/UNINSTALL SUPPORT"), and
- `uninstall`; removes all distribution files from their corresponding locations
  (also see "INSTALL/UNINSTALL SUPPORT").


### Object Files

Object files (the result of compiling a C or C++ source file) have the
extension ".o".


### Programs

Program files are the result of linking object files and libraries together to
form an executable file.  A typical program target looks like:

    program: $(OBJS)
    TAB echo Linking $@...
    TAB $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)

### Static Libraries

Static libraries have a prefix of "lib" and the extension ".a". A typical
static library target looks like:

    libname.a: $(OBJECTS)
    TAB echo Creating $@...
    TAB $(RM) $@
    TAB $(AR) $(ARFLAGS) $@ $(OBJECTS)
    TAB $(RANLIB) $@

### Shared Libraries

Shared libraries have a prefix of "lib" and the extension ".dylib" or ".so"
depending on the operating system.  A typical shared library is composed of
several targets that look like:

    libname.so: $(OBJECTS)
    TAB echo $(DSOCOMMAND) libname.so.$(DSOVERSION) ...
    TAB $(DSOCOMMAND) libname.so.$(DSOVERSION) $(OBJECTS)
    TAB $(RM) libname.so libname.so.$(DSOMAJOR)
    TAB $(LN) libname.so.$(DSOVERSION) libname.so.$(DSOMAJOR)
    TAB $(LN) libname.so.$(DSOVERSION) libname.so

    libname.dylib: $(OBJECTS)
    TAB echo $(DSOCOMMAND) libname.$(DSOVERSION).dylib ...
    TAB $(DSOCOMMAND) libname.$(DSOVERSION).dylib \
    TAB TAB -install_name $(libdir)/libname.$(DSOMAJOR).dylib \
    TAB TAB -current_version libname.$(DSOVERSION).dylib \
    TAB TAB -compatibility_version $(DSOMAJOR).0 \
    TAB TAB $(OBJECTS) $(LIBS)
    TAB $(RM) libname.dylib
    TAB $(RM) libname.$(DSOMAJOR).dylib
    TAB $(LN) libname.$(DSOVERSION).dylib libname.$(DSOMAJOR).dylib
    TAB $(LN) libname.$(DSOVERSION).dylib libname.dylib

### Dependencies

Static dependencies are expressed in each makefile following the target, for
example:

    foo: bar

Static dependencies are only used when it is not possible to automatically
generate them.  Automatic dependencies are stored in a file named
"Dependencies" and included at the end of the makefile.  The following "depend"
target rule is used to create the automatic dependencies:

    depend:
    TAB $(CC) -MM $(ALL_CFLAGS) $(OBJS:.o=.c) >Dependencies

We regenerate the automatic dependencies on an macOS system and express any
non-macOS dependencies statically in the makefile.


### Install/Uninstall Support

All makefiles contains install and uninstall rules which install or remove the
corresponding software.  These rules must use the $(BUILDROOT) variable as a
prefix to any installation directory so that CUPS can be installed in a
temporary location for packaging by programs like rpmbuild.

The `INSTALL_BIN`, `INSTALL_COMPDATA`, `INSTALL_CONFIG`, `INSTALL_DATA`,
`INSTALL_DIR`, `INSTALL_LIB`, `INSTALL_MAN`, and `INSTALL_SCRIPT` variables
must be used when installing files so that the proper ownership and permissions
are set on the installed files.

The `$(RANLIB)` command must be run on any static libraries after installation
since the symbol table is invalidated when the library is copied on some
platforms.