main.c   [plain text]


// This tests DYLD_VERSIONED_LIBRARY_PATH where the library we are doing a versioned check against is only in the shared
// cache and not on disk.  This is the case when macOS moves to MRM.

// libz.1.dylib was chosen as (on 10.15) it had a current version of 1.2.11 so we can write test dylibs with higer/lower versions

// BUILD(macos):  $CC foo.c -dynamiclib -DRESULT="1.0.0"  -current_version 1.0.0  -install_name /usr/lib/libz.1.dylib -o $BUILD_DIR/alt-1.0.0/libz.1.dylib
// BUILD(macos):  $CC foo.c -dynamiclib -DRESULT="2000.0.0"  -current_version 2000.0.0  -install_name /usr/lib/libz.1.dylib -o $BUILD_DIR/alt-2000.0.0/libz.1.dylib

// BUILD(macos):  $CC main.c            -o $BUILD_DIR/env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs.exe -lz
// BUILD(macos):  $CC main.c            -o $BUILD_DIR/env-DYLD_VERSIONED_LIBRARY_PATH-1.0.0.exe -lz -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt-1.0.0
// BUILD(macos):  $CC main.c            -o $BUILD_DIR/env-DYLD_VERSIONED_LIBRARY_PATH-2000.0.0.exe -lz -Wl,-dyld_env,DYLD_VERSIONED_LIBRARY_PATH=@loader_path/alt-2000.0.0
// BUILD(macos):  $CC main.c            -o $BUILD_DIR/env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs-dlopen.exe -DUSE_DLOPEN

// BUILD(macos):  $DYLD_ENV_VARS_ENABLE $BUILD_DIR/env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs.exe
// BUILD(macos):  $DYLD_ENV_VARS_ENABLE $BUILD_DIR/env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs-dlopen.exe

// BUILD(ios,tvos,watchos,bridgeos):

// Use the host when we have no ENV variable, or we check against the 1.0.0 test dylib which is lower than the host
// RUN: ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs.exe "host"
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-1.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs.exe "host"
// RUN: ./env-DYLD_VERSIONED_LIBRARY_PATH-1.0.0.exe "host"
// RUN: ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs-dlopen.exe "host"
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-1.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs-dlopen.exe "host"

// Use the 2000.0.0 dylib when its present
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-2000.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs.exe "2000.0.0"
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-2000.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-1.0.0.exe "2000.0.0"
// RUN: ./env-DYLD_VERSIONED_LIBRARY_PATH-2000.0.0.exe "2000.0.0"
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-2000.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs-dlopen.exe "2000.0.0"

// 2000.0.0 should also override the 1.0.0 version if we specify both (in either order)
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-1.0.0:$RUN_DIR/alt-2000.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs.exe "2000.0.0"
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-2000.0.0:$RUN_DIR/alt-1.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs.exe "2000.0.0"
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-1.0.0:$RUN_DIR/alt-2000.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs-dlopen.exe "2000.0.0"
// RUN: DYLD_VERSIONED_LIBRARY_PATH=$RUN_DIR/alt-2000.0.0:$RUN_DIR/alt-1.0.0 ./env-DYLD_VERSIONED_LIBRARY_PATH-missing-dylibs-dlopen.exe "2000.0.0"

#include <stdio.h>  // fprintf(), NULL
#include <stdlib.h> // exit(), EXIT_SUCCESS
#include <string.h>
#include <stdlib.h> // for atoi()

#include "test_support.h"

#if USE_DLOPEN
#include <dlfcn.h>
#else
extern const char* zlibVersion(); // returns "1.2.11" on the host dylib
#endif

int main(int argc, const char* argv[])
{
	const char* expectedResult = argv[1];

#if USE_DLOPEN
    void * handle = dlopen("/usr/lib/libz.1.dylib", RTLD_LAZY);
    if (!handle) {
        FAIL("dlopen(\"%s\") failed with error \"%s\"", "/usr/lib/libz.1.dylib", dlerror());
    }
    const char* (*zlibVersion)() = dlsym(handle, "zlibVersion");
    if (!zlibVersion) {
        FAIL("dlsym(\"zlibVersion\") failed with error \"%s\"", dlerror());
    }
#endif

    const char* actualResult = zlibVersion();
    if ( !strcmp(expectedResult, "host") ) {
        // We don't know what the host version is, but we know we wanted it instead of the test dylibs
        if ( !strcmp(actualResult, "1.0.0") ) {
            FAIL("Using wrong dylib. zlibVersion() returned %s, expected host version", actualResult);
        } else {
            PASS("Success");
        }
    } else {
        if ( strcmp(actualResult, expectedResult) ) {
            FAIL("Using wrong dylib. zlibVersion() returned %s, expected %s", actualResult, expectedResult);
        } else {
            PASS("Success");
        }
    }
	return 0;
}