diff --git a/include/a2_types.h b/include/a2_types.h index 7788554..6d479be 100644 --- a/include/a2_types.h +++ b/include/a2_types.h @@ -1,7 +1,7 @@ /* * a2_types.h - Audiality 2 basic data types * - * Copyright 2012-2016 David Olofson + * Copyright 2012-2017 David Olofson * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from the @@ -226,6 +226,7 @@ typedef enum A2_sampleformats A2_DEFERR(BADHEXESCAPE, "Bad hex escape format in string literal")\ A2_DEFERR(BADIFNEST, "Nested 'if' without braces")\ A2_DEFERR(BADELSE, "Use of 'else' after non-braced statement")\ + A2_DEFERR(BADLIBVERSION, "Linked A2 lib incompatible with application")\ \ A2_DEFERR(CANTEXPORT, "Cannot export from this scope")\ A2_DEFERR(CANTINPUT, "Unit cannot have inputs")\ diff --git a/include/audiality2.h.cmake b/include/audiality2.h.cmake index 730d6ae..71d7ed4 100644 --- a/include/audiality2.h.cmake +++ b/include/audiality2.h.cmake @@ -1,7 +1,7 @@ /* * audiality2.h - Audiality 2 Realtime Scriptable Audio Engine * - * Copyright 2010-2016 David Olofson + * Copyright 2010-2017 David Olofson * * This software is provided 'as-is', without any express or implied warranty. * In no event will the authors be held liable for any damages arising from the @@ -122,8 +122,27 @@ unsigned a2_LinkedVersion(void); * The 'flags' argument is only passed on to the driver 'flags' field when * a driver is opened by the state! That is, flags are not passed on to a * driver that is already open when a2_Open() is called. + * + * Version checking: + * a2_OpenVersion() verifies that the linked library is compatible with + * the header version specified by the application. If it is not, the call + * will fail with A2_BADLIBVERSION, and return NULL. + * + * a2_Open() automatically passes the version of the headers the + * application is compiled against, which means that applications using + * this call will not work with older library versions; only same or + * newer. + * + * When distributing binaries, it may be useful to specify the Audiality 2 + * version explicitly via a2_OpenVersion(), so that applications will not + * be prevented from running with older libraries, unless they actually + * need features added in later versions. */ -A2_interface *a2_Open(A2_config *config); +A2_interface *a2_OpenVersion(A2_config *config, unsigned headerversion); +static inline A2_interface *a2_Open(A2_config *config) +{ + return a2_OpenVersion(config, a2_HeaderVersion()); +} /* * Create a substate to the state behind interface 'master'. diff --git a/src/audiality2.c b/src/audiality2.c index 882b1c5..61bbfd5 100644 --- a/src/audiality2.c +++ b/src/audiality2.c @@ -514,12 +514,57 @@ static A2_errors a2_Open2(A2_state *st) } -A2_interface *a2_Open(A2_config *config) +static A2_errors a2_verify_version(unsigned headerversion) +{ + /* Major and minor versions need to match. */ + if((A2_MAJOR(headerversion) == A2_MAJOR(A2_VERSION)) && + (A2_MINOR(headerversion) == A2_MINOR(A2_VERSION))) + { + if(A2_MINOR(A2_VERSION) & 1) + { + /* + * Development branches are assumed to break binary + * compatibility with every micro release! + */ + if(A2_MICRO(headerversion) == A2_MICRO(A2_VERSION)) + return A2_OK; + } + else + { + /* + * Stable branch; lib needs to be of same or higher + * micro version. + */ + if(A2_MICRO(headerversion) <= A2_MICRO(A2_VERSION)) + return A2_OK; + } + } + + /* Check failed! This will not work. */ + fprintf(stderr, "CRITICAL: Incompatible Audiality library!\n"); + fprintf(stderr, "This library is version %d.%d.%d.%d\n", + A2_MAJOR(A2_VERSION), + A2_MINOR(A2_VERSION), + A2_MICRO(A2_VERSION), + A2_BUILD(A2_VERSION)); + fprintf(stderr, "Application is built for %d.%d.%d.%d\n", + A2_MAJOR(headerversion), + A2_MINOR(headerversion), + A2_MICRO(headerversion), + A2_BUILD(headerversion)); + return A2_BADLIBVERSION; +} + + +A2_interface *a2_OpenVersion(A2_config *config, unsigned headerversion) { A2_errors res; A2_state *st; A2_interface_i *j; - a2_last_error = A2_OK; + + if((a2_last_error = a2_verify_version(headerversion))) + return NULL; + DUMPSIZES( printf("A2_wave:\t%d\n", sizeof(A2_wave)); printf("A2_bank:\t%d\n", sizeof(A2_bank));