| 29 | #include "fl/stl/noexcept.h" |
| 30 | |
| 31 | int main(int argc, char** argv) FL_NOEXCEPT { |
| 32 | // Setup crash handler BEFORE loading any shared libraries |
| 33 | runner_setup_crash_handler(); |
| 34 | |
| 35 | // Setup timeout watchdog to detect hung examples |
| 36 | timeout_watchdog::setup(); // Default: 20 seconds, configurable via FASTLED_TEST_TIMEOUT |
| 37 | |
| 38 | std::string so_path; |
| 39 | const std::string shared_lib_ext = ".dylib"; |
| 40 | |
| 41 | // Determine shared library path: explicit argument or inferred from exe name |
| 42 | if (argc > 1 && argv[1][0] != '-') { |
| 43 | // First argument is a path (doesn't start with -) |
| 44 | so_path = argv[1]; |
| 45 | } else { |
| 46 | // No explicit path: infer from exe name |
| 47 | std::string full_exe_path; |
| 48 | char path_buf[1024]; |
| 49 | fl::u32 buf_size = sizeof(path_buf); |
| 50 | if (_NSGetExecutablePath(path_buf, &buf_size) == 0) { |
| 51 | full_exe_path = path_buf; |
| 52 | } else { |
| 53 | // Buffer too small, fallback to argv[0] |
| 54 | full_exe_path = argv[0]; |
| 55 | } |
| 56 | |
| 57 | if (full_exe_path.empty()) { |
| 58 | std::cout << "Error: Failed to get executable path" << std::endl; |
| 59 | return 1; |
| 60 | } |
| 61 | |
| 62 | // Extract directory and filename |
| 63 | size_t last_slash = full_exe_path.find_last_of('/'); |
| 64 | std::string exe_dir = (last_slash != std::string::npos) ? full_exe_path.substr(0, last_slash) : "."; |
| 65 | std::string exe_file = (last_slash != std::string::npos) ? full_exe_path.substr(last_slash + 1) : full_exe_path; |
| 66 | |
| 67 | // Remove executable extension (if any) |
| 68 | size_t dot_pos = exe_file.find_last_of('.'); |
| 69 | std::string exe_name = (dot_pos != std::string::npos) ? exe_file.substr(0, dot_pos) : exe_file; |
| 70 | |
| 71 | // Construct shared library path |
| 72 | std::string so_name = exe_name + shared_lib_ext; |
| 73 | so_path = exe_dir + "/" + so_name; |
| 74 | } |
| 75 | |
| 76 | // Load shared library with RTLD_NOW for immediate symbol resolution |
| 77 | // This helps ASAN properly track symbols from the loaded library |
| 78 | void* handle = dlopen(so_path.c_str(), RTLD_NOW | RTLD_GLOBAL); |
| 79 | if (!handle) { |
| 80 | std::cout << "Error: Failed to load " << so_path << " (" << dlerror() << ")" << std::endl; |
| 81 | return 1; |
| 82 | } |
| 83 | |
| 84 | // Get run_example function |
| 85 | RunExampleFunc run_example = (RunExampleFunc)dlsym(handle, "run_example"); |
| 86 | if (!run_example) { |
| 87 | std::cout << "Error: Failed to find run_example() in " << so_path << " (" << dlerror() << ")" << std::endl; |
| 88 | dlclose(handle); |
nothing calls this directly
no test coverage detected