├── LICENSE ├── README.md ├── launch └── launch.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Munawwar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Launcher 2 | 3 | Cross-platform binary launcher 4 | 5 | Download the `launch` binary from https://github.com/Munawwar/launcher/releases/tag/v0.1.0 6 | 7 | Usage: `launch [binary name]` 8 | 9 | Lets say you have a list of binaries like the following: 10 | ``` 11 | goaws-linux-x86_64 12 | goaws-darwin-arm64 13 | goaws-darwin-x86_64 14 | goaws-windows-x86_64.exe 15 | ``` 16 | 17 | And lets say you want a single command to pick and execute the correct binary on a developer's machine based on the OS they use. 18 | 19 | Then you can ship `launch` binary and run 20 | 21 | ```sh 22 | launch goaws 23 | ``` 24 | (`goaws` is just an example here, could be any prefix) 25 | 26 | And that will run the correct `goaws` binary from the current working directory. 27 | 28 | Following OS and architecture filename suffixes are supported: 29 | ``` 30 | -linux-x86_64 31 | -linux-arm64 32 | -darwin-x86_64 33 | -darwin-arm64 34 | -windows-x86_64.exe 35 | -windows-arm64.exe 36 | -bsd-x86_64 37 | -bsd-arm64 38 | ``` 39 | 40 | ## Build the binary yourself? 41 | 42 | Download cosmo compiler 43 | ```sh 44 | mkdir -p cosmocc 45 | cd cosmocc 46 | wget https://cosmo.zip/pub/cosmocc/cosmocc.zip 47 | unzip cosmocc.zip 48 | cd .. 49 | ``` 50 | 51 | Next, build the file: 52 | ```sh 53 | cosmocc/bin/cosmocc -o launch launch.c 54 | ``` 55 | -------------------------------------------------------------------------------- /launch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Munawwar/launcher/532eb58d16d6088f7e264f29dbcdb072c633f471/launch -------------------------------------------------------------------------------- /launch.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | const char* detect_os() { 9 | struct utsname buffer; 10 | if (uname(&buffer) == 0) { 11 | if (strstr(buffer.sysname, "Linux") != NULL) { 12 | return "linux"; 13 | } else if (strstr(buffer.sysname, "Darwin") != NULL) { 14 | return "darwin"; 15 | } else if ( 16 | strstr(buffer.sysname, "FreeBSD") != NULL || 17 | strstr(buffer.sysname, "OpenBSD") != NULL || 18 | strstr(buffer.sysname, "NetBSD") != NULL 19 | ) { 20 | return "bsd"; 21 | } else if (strstr(buffer.sysname, "Windows") != NULL) { 22 | return "windows"; 23 | } 24 | } 25 | return "unknown"; 26 | } 27 | 28 | const char* detect_arch() { 29 | struct utsname buffer; 30 | if (uname(&buffer) == 0) { 31 | if (strstr(buffer.machine, "x86_64") != NULL || 32 | strstr(buffer.machine, "amd64") != NULL) { 33 | return "x86_64"; 34 | } 35 | if (strstr(buffer.machine, "aarch64") != NULL || 36 | strstr(buffer.machine, "arm64") != NULL) { 37 | return "arm64"; 38 | } 39 | if (strstr(buffer.machine, "armv7") != NULL) { 40 | return "armv7"; 41 | } 42 | if (strstr(buffer.machine, "armv6") != NULL) { 43 | return "armv6"; 44 | } 45 | // Generic ARM detection 46 | if (strstr(buffer.machine, "arm") != NULL) { 47 | // Try to determine ARM version 48 | FILE *cpuinfo = fopen("/proc/cpuinfo", "r"); 49 | if (cpuinfo) { 50 | char line[256]; 51 | while (fgets(line, sizeof(line), cpuinfo)) { 52 | if (strstr(line, "ARMv7") != NULL) { 53 | fclose(cpuinfo); 54 | return "armv7"; 55 | } else if (strstr(line, "ARMv6") != NULL) { 56 | fclose(cpuinfo); 57 | return "armv6"; 58 | } 59 | } 60 | fclose(cpuinfo); 61 | // Default to ARMv7 for generic ARM 62 | return "armv7"; 63 | } 64 | // If we can't determine the version, assume ARMv7 65 | return "armv7"; 66 | } 67 | return "unknown"; 68 | } 69 | 70 | // Fallback to pointer size 71 | if (sizeof(void*) == 8) { 72 | return "x86_64"; // Assume x86_64 for 64-bit 73 | } else { 74 | return "x86"; // Assume x86 for 32-bit 75 | } 76 | } 77 | 78 | int main(int argc, char *argv[]) { 79 | const char *binary_path = NULL; 80 | const char *binary_prefix = NULL; 81 | char path_buffer[256]; 82 | 83 | // Get binary prefix from command line 84 | if (argc < 2) { 85 | fprintf(stderr, "Usage: %s [args...]\n", argv[0]); 86 | fprintf(stderr, "Example: %s goaws-0.5.2\n", argv[0]); 87 | return 1; 88 | } 89 | 90 | binary_prefix = argv[1]; 91 | 92 | // Detect OS and architecture safely 93 | const char *os = detect_os(); 94 | const char *arch = detect_arch(); 95 | 96 | printf("Detected OS: %s\n", os); 97 | printf("Detected architecture: %s\n", arch); 98 | 99 | // Construct binary path based on detected OS and architecture 100 | if (strcmp(os, "windows") == 0) { 101 | snprintf(path_buffer, sizeof(path_buffer), "%s-%s-%s.exe", binary_prefix, os, arch); 102 | } else { 103 | snprintf(path_buffer, sizeof(path_buffer), "%s-%s-%s", binary_prefix, os, arch); 104 | } 105 | 106 | binary_path = path_buffer; 107 | printf("Looking for binary: %s\n", binary_path); 108 | 109 | // Check if the binary exists 110 | if (access(binary_path, X_OK) != 0) { 111 | fprintf(stderr, "Binary %s not found or not executable\n", binary_path); 112 | return 1; 113 | } 114 | 115 | printf("Launching: %s\n", binary_path); 116 | 117 | // Forward all arguments to the selected binary (skipping our binary name and the prefix argument) 118 | char *new_argv[argc]; 119 | new_argv[0] = (char *)binary_path; 120 | for (int i = 2; i < argc; i++) { 121 | new_argv[i-1] = argv[i]; 122 | } 123 | new_argv[argc-1] = NULL; 124 | 125 | // Execute the selected binary 126 | execv(binary_path, new_argv); 127 | 128 | // If execv succeeded, we won't reach here. If it does, execv failed 129 | fprintf(stderr, "Failed to execute %s: %s\n", binary_path, strerror(errno)); 130 | return 1; 131 | } --------------------------------------------------------------------------------