Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Semantic versioning: minor or major change?

In semantic versioning the general rule is to increase the minor number only when backwards compatible functionalities are introduced, otherwise the major number must be increased instead. The same approach, but with a different arithmetic, is used by libtool.

I have a question concerning what is considered a backwards compatible change and what not.

Imagine I have written a library, and the public header of this library contains a typedef of a data type named foo. In version 1.0.0 this typedef looks like this:

typedef struct foo_t {
    int x;
    int y;
} foo;

Then I decide to change the data type, and in the next version it will look like this:

typedef struct foo_t {
    int x;
    int y;
    int z;
} foo;

I have only added one field to the structure foo_t. It would seem to be a backward compatible change, however the structure above is de facto another structure now. What I have done was not introducing a new function and leave untouched all the rest, but instead I have changed something that was already there.

The data type above is normally used for exchanging data with the library's functions, however the user might have used it with other purposes. If the user had written a program using version 1.0.0 and the last change constitutes a backward compatible change, the user's program must compile also with this new version.

How will this new version be called, 1.1.0 or 2.0.0?

EDIT

You can read further developments of this discussion here.

like image 388
madmurphy Avatar asked Mar 10 '19 13:03

madmurphy


People also ask

What is major version in semantic versioning?

Semantic Versioning is a 3-component number in the format of X.Y.Z, where : X stands for a major version. The leftmost number denotes a major version. When you increase the major version number, you increase it by one but you reset both patch version and minor versions to zero.

When should I change my minor version?

Minor version Y (x.Y.z | x > 0) MUST be incremented if new, backwards compatible functionality is introduced to the public API. It MUST be incremented if any public API functionality is marked as deprecated. It MAY be incremented if substantial new functionality or improvements are introduced within the private code.

What are major and minor versions?

When you track major and minor versions, the major versions are whole numbers, and the minor versions are decimals. For example, 0.1 is the first minor version of a file, 1.3 is the third minor version of a file that was published once, and 2.0 is the second major version of a published file.

Is a SemVer major change?

Major change: a change that requires a major SemVer bump. Minor change: a change that requires only a minor SemVer bump. Possibly-breaking change: a change that some projects may consider major and others consider minor.


1 Answers

It would be a major version change. Struct layouts are baked into end user programs. It is a breaking change to add or remove members; either way, the layout has changed.

Quoting from the Linux Program Library HOWTO — §3.6. Incompatible Libraries:

When a new version of a library is binary-incompatible with the old one the soname needs to change. In C, there are four basic reasons that a library would cease to be binary compatible:

  1. The behavior of a function changes so that it no longer meets its original specification,

  2. Exported data items change (exception: adding optional items to the ends of structures is okay, as long as those structures are only allocated within the library).

  3. An exported function is removed.

  4. The interface of an exported function changes.

You say, "The data type above is normally used for exchanging data with the library's functions, however the user might have used it with other purposes." If the struct were used internally only and not exposed in the public API you'd be okay. But it sounds like the user could allocate a struct variable themselves, which means it's a breaking change.

You can protect your library from this type of churn by using opaque structs. Hide the contents of the structs and have the user just pass around pointers. This is exactly how FILE * works: the C standard doesn't define the layout of FILE and we as end users don't know what's inside of it.

like image 89
John Kugelman Avatar answered Oct 11 '22 03:10

John Kugelman