diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2022-04-24 19:53:36 +0200 |
|---|---|---|
| committer | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2022-04-24 19:53:36 +0200 |
| commit | 63331ef731209ec8db65d7f26bdbebdf9459107d (patch) | |
| tree | 5821f52c432a07d374fddc4b89d8a466833b3734 /src | |
| parent | a40a53b10447c9223c24cccf565a95f1773d3922 (diff) | |
Revert "Merge pull request #1702 from Kelimion/filename_generation"
This reverts commit a40a53b10447c9223c24cccf565a95f1773d3922, reversing
changes made to 5422a3b17eae821df4adf869960995e922eb0e76.
Diffstat (limited to 'src')
| -rw-r--r-- | src/build_settings.cpp | 208 | ||||
| -rw-r--r-- | src/common.cpp | 257 | ||||
| -rw-r--r-- | src/gb/gb.h | 46 | ||||
| -rw-r--r-- | src/llvm_backend.cpp | 14 | ||||
| -rw-r--r-- | src/llvm_backend_general.cpp | 1 | ||||
| -rw-r--r-- | src/main.cpp | 152 | ||||
| -rw-r--r-- | src/parser.cpp | 2 | ||||
| -rw-r--r-- | src/path.cpp | 333 | ||||
| -rw-r--r-- | src/string.cpp | 10 |
9 files changed, 383 insertions, 640 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 212ded5c8..2f3eb03a5 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -3,6 +3,7 @@ #include <sys/sysctl.h> #endif + // #if defined(GB_SYSTEM_WINDOWS) // #define DEFAULT_TO_THREADED_CHECKER // #endif @@ -197,22 +198,6 @@ enum RelocMode : u8 { RelocMode_DynamicNoPIC, }; -enum BuildPath : u8 { - BuildPath_Main_Package, // Input Path to the package directory (or file) we're building. - BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`. - BuildPath_RES, // Output Path for .res file, generated from previous. - BuildPath_Win_SDK_Root, // windows_sdk_root - BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path - BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path - BuildPath_VS_EXE, // vs_exe_path - BuildPath_VS_LIB, // vs_library_path - - BuildPath_Output, // Output Path for .exe, .dll, .so, etc. Can be overridden with `-out:`. - BuildPath_PDB, // Output Path for .pdb file, can be overridden with `-pdb-name:`. - - BuildPathCOUNT, -}; - // This stores the information for the specify architecture of this build struct BuildContext { // Constants @@ -241,13 +226,9 @@ struct BuildContext { bool show_help; - Array<Path> build_paths; // Contains `Path` objects to output filename, pdb, resource and intermediate files. - // BuildPath enum contains the indices of paths we know *before* the work starts. - String out_filepath; String resource_filepath; String pdb_filepath; - bool has_resource; String link_flags; String extra_linker_flags; @@ -319,6 +300,8 @@ struct BuildContext { }; + + gb_global BuildContext build_context = {0}; bool global_warnings_as_errors(void) { @@ -622,6 +605,28 @@ bool allow_check_foreign_filepath(void) { // is_abs_path // has_subdir +enum TargetFileValidity : u8 { + TargetFileValidity_Invalid, + + TargetFileValidity_Writable_File, + TargetFileValidity_No_Write_Permission, + TargetFileValidity_Directory, + + TargetTargetFileValidity_COUNT, +}; + +TargetFileValidity set_output_filename(void) { + // Assembles the output filename from build_context information. + // Returns `true` if it doesn't exist or is a file. + // Returns `false` if a directory or write-protected file. + + + + + return TargetFileValidity_Writable_File; +} + + String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1}; String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1}; @@ -968,6 +973,7 @@ char *token_pos_to_string(TokenPos const &pos) { return s; } + void init_build_context(TargetMetrics *cross_target) { BuildContext *bc = &build_context; @@ -1146,166 +1152,8 @@ void init_build_context(TargetMetrics *cross_target) { bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3); + + #undef LINK_FLAG_X64 #undef LINK_FLAG_386 } - -#if defined(GB_SYSTEM_WINDOWS) -// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. -// NOTE(Jeroen): No longer needed in `main.cpp -> linker_stage`. We now resolve those paths in `init_build_paths`. -#include "microsoft_craziness.h" -#endif - -// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate. -// We've previously called `parse_build_flags`, so `out_filepath` should be set. -bool init_build_paths(String init_filename) { - gbAllocator ha = heap_allocator(); - BuildContext *bc = &build_context; - - // NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index. - array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT); - - // [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path. - bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename); - - bool produces_output_file = false; - if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { - produces_output_file = true; - } else if (bc->command_kind & Command__does_build) { - produces_output_file = true; - } - - if (!produces_output_file) { - // Command doesn't produce output files. We're done. - return true; - } - - #if defined(GB_SYSTEM_WINDOWS) - if (bc->resource_filepath.len > 0) { - bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); - bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); - bc->build_paths[BuildPath_RC].ext = copy_string(ha, STR_LIT("rc")); - bc->build_paths[BuildPath_RES].ext = copy_string(ha, STR_LIT("res")); - } - - if (bc->pdb_filepath.len > 0) { - bc->build_paths[BuildPath_PDB] = path_from_string(ha, bc->pdb_filepath); - } - - if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { - // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. - Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); - - if (find_result.windows_sdk_version == 0) { - gb_printf_err("Windows SDK not found.\n"); - return false; - } - - GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); - GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); - - if (find_result.windows_sdk_root.len > 0) { - bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); - } - - if (find_result.windows_sdk_um_library_path.len > 0) { - bc->build_paths[BuildPath_Win_SDK_UM_Lib] = path_from_string(ha, find_result.windows_sdk_um_library_path); - } - - if (find_result.windows_sdk_ucrt_library_path.len > 0) { - bc->build_paths[BuildPath_Win_SDK_UCRT_Lib] = path_from_string(ha, find_result.windows_sdk_ucrt_library_path); - } - - if (find_result.vs_exe_path.len > 0) { - bc->build_paths[BuildPath_VS_EXE] = path_from_string(ha, find_result.vs_exe_path); - } - - if (find_result.vs_library_path.len > 0) { - bc->build_paths[BuildPath_VS_LIB] = path_from_string(ha, find_result.vs_library_path); - } - - gb_free(ha, find_result.windows_sdk_root.text); - gb_free(ha, find_result.windows_sdk_um_library_path.text); - gb_free(ha, find_result.windows_sdk_ucrt_library_path.text); - gb_free(ha, find_result.vs_exe_path.text); - gb_free(ha, find_result.vs_library_path.text); - - } - #endif - - // All the build targets and OSes. - String output_extension; - - if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) { - output_extension = STR_LIT("odin-doc"); - } else if (is_arch_wasm()) { - output_extension = STR_LIT("wasm"); - } else if (build_context.build_mode == BuildMode_Executable) { - // By default use a .bin executable extension. - output_extension = STR_LIT("bin"); - - if (build_context.metrics.os == TargetOs_windows) { - output_extension = STR_LIT("exe"); - } else if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { - output_extension = make_string(nullptr, 0); - } - } else if (build_context.build_mode == BuildMode_DynamicLibrary) { - // By default use a .so shared library extension. - output_extension = STR_LIT("so"); - - if (build_context.metrics.os == TargetOs_windows) { - output_extension = STR_LIT("dll"); - } else if (build_context.metrics.os == TargetOs_darwin) { - output_extension = STR_LIT("dylib"); - } - } else if (build_context.build_mode == BuildMode_Object) { - // By default use a .o object extension. - output_extension = STR_LIT("o"); - - if (build_context.metrics.os == TargetOs_windows) { - output_extension = STR_LIT("obj"); - } - } else if (build_context.build_mode == BuildMode_Assembly) { - // By default use a .S asm extension. - output_extension = STR_LIT("S"); - } else if (build_context.build_mode == BuildMode_LLVM_IR) { - output_extension = STR_LIT("ll"); - } else { - GB_PANIC("Unhandled build mode/target combination.\n"); - } - - if (bc->out_filepath.len > 0) { - bc->build_paths[BuildPath_Output] = path_from_string(ha, bc->out_filepath); - } else { - String output_name = remove_directory_from_path(init_filename); - output_name = remove_extension_from_path(output_name); - output_name = copy_string(ha, string_trim_whitespace(output_name)); - - Path output_path = path_from_string(ha, output_name); - - // Replace extension. - if (output_path.ext.len > 0) { - gb_free(ha, output_path.ext.text); - } - output_path.ext = copy_string(ha, output_extension); - - bc->build_paths[BuildPath_Output] = output_path; - } - - // Do we have an extension? We might not if the output filename was supplied. - if (bc->build_paths[BuildPath_Output].ext.len == 0) { - if (build_context.metrics.os == TargetOs_windows || build_context.build_mode != BuildMode_Executable) { - bc->build_paths[BuildPath_Output].ext = copy_string(ha, output_extension); - } - } - - // Check if output path is a directory. - if (path_is_directory(bc->build_paths[BuildPath_Output])) { - String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); - defer (gb_free(ha, output_file.text)); - gb_printf_err("Output path %.*s is a directory.\n", LIT(output_file)); - return false; - } - - return true; -}
\ No newline at end of file diff --git a/src/common.cpp b/src/common.cpp index 94248fb62..aaacda04b 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -675,7 +675,262 @@ wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) { #endif -#include "path.cpp" + +#if defined(GB_SYSTEM_WINDOWS) + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + String16 wstr = string_to_string16(a, path); + defer (gb_free(a, wstr.text)); + + i32 attribs = GetFileAttributesW(wstr.text); + if (attribs < 0) return false; + + return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0; + } + +#else + bool path_is_directory(String path) { + gbAllocator a = heap_allocator(); + char *copy = cast(char *)copy_string(a, path).text; + defer (gb_free(a, copy)); + + struct stat s; + if (stat(copy, &s) == 0) { + return (s.st_mode & S_IFDIR) != 0; + } + return false; + } +#endif + + +String path_to_full_path(gbAllocator a, String path) { + gbAllocator ha = heap_allocator(); + char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len); + defer (gb_free(ha, path_c)); + + char *fullpath = gb_path_get_full_name(a, path_c); + String res = string_trim_whitespace(make_string_c(fullpath)); +#if defined(GB_SYSTEM_WINDOWS) + for (isize i = 0; i < res.len; i++) { + if (res.text[i] == '\\') { + res.text[i] = '/'; + } + } +#endif + return res; +} + + + +struct FileInfo { + String name; + String fullpath; + i64 size; + bool is_dir; +}; + +enum ReadDirectoryError { + ReadDirectory_None, + + ReadDirectory_InvalidPath, + ReadDirectory_NotExists, + ReadDirectory_Permission, + ReadDirectory_NotDir, + ReadDirectory_Empty, + ReadDirectory_Unknown, + + ReadDirectory_COUNT, +}; + +i64 get_file_size(String path) { + char *c_str = alloc_cstring(heap_allocator(), path); + defer (gb_free(heap_allocator(), c_str)); + + gbFile f = {}; + gbFileError err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + if (err != gbFileError_None) { + return -1; + } + return gb_file_size(&f); +} + + +#if defined(GB_SYSTEM_WINDOWS) +ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + while (path.len > 0) { + Rune end = path[path.len-1]; + if (end == '/') { + path.len -= 1; + } else if (end == '\\') { + path.len -= 1; + } else { + break; + } + } + + if (path.len == 0) { + return ReadDirectory_InvalidPath; + } + { + char *c_str = alloc_cstring(a, path); + defer (gb_free(a, c_str)); + + gbFile f = {}; + gbFileError file_err = gb_file_open(&f, c_str); + defer (gb_file_close(&f)); + + switch (file_err) { + case gbFileError_Invalid: return ReadDirectory_InvalidPath; + case gbFileError_NotExists: return ReadDirectory_NotExists; + // case gbFileError_Permission: return ReadDirectory_Permission; + } + } + + if (!path_is_directory(path)) { + return ReadDirectory_NotDir; + } + + + char *new_path = gb_alloc_array(a, char, path.len+3); + defer (gb_free(a, new_path)); + + gb_memmove(new_path, path.text, path.len); + gb_memmove(new_path+path.len, "/*", 2); + new_path[path.len+2] = 0; + + String np = make_string(cast(u8 *)new_path, path.len+2); + String16 wstr = string_to_string16(a, np); + defer (gb_free(a, wstr.text)); + + WIN32_FIND_DATAW file_data = {}; + HANDLE find_file = FindFirstFileW(wstr.text, &file_data); + if (find_file == INVALID_HANDLE_VALUE) { + return ReadDirectory_Unknown; + } + defer (FindClose(find_file)); + + array_init(fi, a, 0, 100); + + do { + wchar_t *filename_w = file_data.cFileName; + i64 size = cast(i64)file_data.nFileSizeLow; + size |= (cast(i64)file_data.nFileSizeHigh) << 32; + String name = string16_to_string(a, make_string16_c(filename_w)); + if (name == "." || name == "..") { + gb_free(a, name.text); + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + array_add(fi, info); + } while (FindNextFileW(find_file, &file_data)); + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) + +#include <dirent.h> + +ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) { + GB_ASSERT(fi != nullptr); + + gbAllocator a = heap_allocator(); + + char *c_path = alloc_cstring(a, path); + defer (gb_free(a, c_path)); + + DIR *dir = opendir(c_path); + if (!dir) { + switch (errno) { + case ENOENT: + return ReadDirectory_NotExists; + case EACCES: + return ReadDirectory_Permission; + case ENOTDIR: + return ReadDirectory_NotDir; + default: + // ENOMEM: out of memory + // EMFILE: per-process limit on open fds reached + // ENFILE: system-wide limit on total open files reached + return ReadDirectory_Unknown; + } + GB_PANIC("unreachable"); + } + + array_init(fi, a, 0, 100); + + for (;;) { + struct dirent *entry = readdir(dir); + if (entry == nullptr) { + break; + } + + String name = make_string_c(entry->d_name); + if (name == "." || name == "..") { + continue; + } + + String filepath = {}; + filepath.len = path.len+1+name.len; + filepath.text = gb_alloc_array(a, u8, filepath.len+1); + defer (gb_free(a, filepath.text)); + gb_memmove(filepath.text, path.text, path.len); + gb_memmove(filepath.text+path.len, "/", 1); + gb_memmove(filepath.text+path.len+1, name.text, name.len); + filepath.text[filepath.len] = 0; + + + struct stat dir_stat = {}; + + if (stat((char *)filepath.text, &dir_stat)) { + continue; + } + + if (S_ISDIR(dir_stat.st_mode)) { + continue; + } + + i64 size = dir_stat.st_size; + + FileInfo info = {}; + info.name = name; + info.fullpath = path_to_full_path(a, filepath); + info.size = size; + array_add(fi, info); + } + + if (fi->count == 0) { + return ReadDirectory_Empty; + } + + return ReadDirectory_None; +} +#else +#error Implement read_directory +#endif + + struct LoadedFile { void *handle; diff --git a/src/gb/gb.h b/src/gb/gb.h index 3b2d6434c..b72a893f7 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -6273,44 +6273,20 @@ char *gb_path_get_full_name(gbAllocator a, char const *path) { #else char *p, *result, *fullpath = NULL; isize len; - fullpath = realpath(path, NULL); - - if (fullpath == NULL) { - // NOTE(Jeroen): Path doesn't exist. - if (gb_strlen(path) > 0 && path[0] == '/') { - // But it is an absolute path, so return as-is. - - fullpath = (char *)path; - len = gb_strlen(fullpath) + 1; - result = gb_alloc_array(a, char, len + 1); - - gb_memmove(result, fullpath, len); - result[len] = 0; - - } else { - // Appears to be a relative path, so construct an absolute one relative to <cwd>. - char cwd[4096]; - getcwd(&cwd[0], 4096); - - isize path_len = gb_strlen(path); - isize cwd_len = gb_strlen(cwd); - len = cwd_len + 1 + path_len + 1; - result = gb_alloc_array(a, char, len); + p = realpath(path, NULL); + fullpath = p; + if (p == NULL) { + // NOTE(bill): File does not exist + fullpath = cast(char *)path; + } - gb_memmove(result, (void *)cwd, cwd_len); - result[cwd_len] = '/'; + len = gb_strlen(fullpath); - gb_memmove(result + cwd_len + 1, (void *)path, gb_strlen(path)); - result[len] = 0; + result = gb_alloc_array(a, char, len + 1); + gb_memmove(result, fullpath, len); + result[len] = 0; + free(p); - } - } else { - len = gb_strlen(fullpath) + 1; - result = gb_alloc_array(a, char, len + 1); - gb_memmove(result, fullpath, len); - result[len] = 0; - free(fullpath); - } return result; #endif } diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 7781997f7..f5cb84785 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -967,12 +967,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime) } String lb_filepath_ll_for_module(lbModule *m) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); - + String path = m->gen->output_base; if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } else if (USE_SEPARATE_MODULES) { @@ -983,12 +978,7 @@ String lb_filepath_ll_for_module(lbModule *m) { return path; } String lb_filepath_obj_for_module(lbModule *m) { - String path = concatenate3_strings(permanent_allocator(), - build_context.build_paths[BuildPath_Output].basename, - STR_LIT("/"), - build_context.build_paths[BuildPath_Output].name - ); - + String path = m->gen->output_base; if (m->pkg) { path = concatenate3_strings(permanent_allocator(), path, STR_LIT("-"), m->pkg->name); } diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 1a431a4ac..330059622 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -87,6 +87,7 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) { return false; } + String init_fullpath = c->parser->init_fullpath; if (build_context.out_filepath.len == 0) { diff --git a/src/main.cpp b/src/main.cpp index 7b0364149..fc8792ceb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -46,6 +46,7 @@ gb_global Timings global_timings = {0}; #include "checker.cpp" #include "docs.cpp" + #include "llvm_backend.cpp" #if defined(GB_SYSTEM_OSX) @@ -56,8 +57,16 @@ gb_global Timings global_timings = {0}; #endif #include "query_data.cpp" + + +#if defined(GB_SYSTEM_WINDOWS) +// NOTE(IC): In order to find Visual C++ paths without relying on environment variables. +#include "microsoft_craziness.h" +#endif + #include "bug_report.cpp" + // NOTE(bill): 'name' is used in debugging and profiling modes i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { isize const cmd_cap = 64<<20; // 64 MiB should be more than enough @@ -121,35 +130,34 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) { } + + i32 linker_stage(lbGenerator *gen) { i32 result = 0; Timings *timings = &global_timings; - String output_filename = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); - debugf("Linking %.*s\n", LIT(output_filename)); - - // TOOD(Jeroen): Make a `build_paths[BuildPath_Object] to avoid `%.*s.o`. + String output_base = gen->output_base; if (is_arch_wasm()) { timings_start_section(timings, str_lit("wasm-ld")); #if defined(GB_SYSTEM_WINDOWS) result = system_exec_command_line_app("wasm-ld", - "\"%.*s\\bin\\wasm-ld\" \"%.*s.o\" -o \"%.*s\" %.*s %.*s", + "\"%.*s\\bin\\wasm-ld\" \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", LIT(build_context.ODIN_ROOT), - LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else result = system_exec_command_line_app("wasm-ld", - "wasm-ld \"%.*s.o\" -o \"%.*s\" %.*s %.*s", - LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + "wasm-ld \"%.*s.wasm.o\" -o \"%.*s.wasm\" %.*s %.*s", + LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #endif return result; } if (build_context.cross_compiling && selected_target_metrics->metrics == &target_essence_amd64) { -#if defined(GB_SYSTEM_UNIX) +#ifdef GB_SYSTEM_UNIX result = system_exec_command_line_app("linker", "x86_64-essence-gcc \"%.*s.o\" -o \"%.*s\" %.*s %.*s", - LIT(output_filename), LIT(output_filename), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); + LIT(output_base), LIT(output_base), LIT(build_context.link_flags), LIT(build_context.extra_linker_flags)); #else gb_printf_err("Linking for cross compilation for this platform is not yet supported (%.*s %.*s)\n", LIT(target_os_names[build_context.metrics.os]), @@ -173,11 +181,28 @@ i32 linker_stage(lbGenerator *gen) { gbString lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(lib_str)); + char const *output_ext = "exe"; gbString link_settings = gb_string_make_reserve(heap_allocator(), 256); defer (gb_string_free(link_settings)); + + // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. + Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); + + if (find_result.windows_sdk_version == 0) { + gb_printf_err("Windows SDK not found.\n"); + exit(1); + } + + if (build_context.ignore_microsoft_magic) { + find_result = {}; + } + // Add library search paths. - if (build_context.build_paths[BuildPath_VS_LIB].basename.len > 0) { + if (find_result.vs_library_path.len > 0) { + GB_ASSERT(find_result.windows_sdk_um_library_path.len > 0); + GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); + String path = {}; auto add_path = [&](String path) { if (path[path.len-1] == '\\') { @@ -185,9 +210,9 @@ i32 linker_stage(lbGenerator *gen) { } link_settings = gb_string_append_fmt(link_settings, " /LIBPATH:\"%.*s\"", LIT(path)); }; - add_path(build_context.build_paths[BuildPath_Win_SDK_UM_Lib].basename); - add_path(build_context.build_paths[BuildPath_Win_SDK_UCRT_Lib].basename); - add_path(build_context.build_paths[BuildPath_VS_LIB].basename); + add_path(find_result.windows_sdk_um_library_path); + add_path(find_result.windows_sdk_ucrt_library_path); + add_path(find_result.vs_library_path); } @@ -227,14 +252,14 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.build_mode == BuildMode_DynamicLibrary) { + output_ext = "dll"; link_settings = gb_string_append_fmt(link_settings, " /DLL"); } else { link_settings = gb_string_append_fmt(link_settings, " /ENTRY:mainCRTStartup"); } if (build_context.pdb_filepath != "") { - String pdb_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_PDB]); - link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(pdb_path)); + link_settings = gb_string_append_fmt(link_settings, " /PDB:%.*s", LIT(build_context.pdb_filepath)); } if (build_context.no_crt) { @@ -275,21 +300,13 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } - String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]); - defer (gb_free(heap_allocator(), vs_exe_path.text)); - char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; if (!build_context.use_lld) { // msvc if (build_context.has_resource) { - String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]); - String res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]); - defer (gb_free(heap_allocator(), rc_path.text)); - defer (gb_free(heap_allocator(), res_path.text)); - result = system_exec_command_line_app("msvc-link", - "\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"", - LIT(res_path), - LIT(rc_path) + "\"rc.exe\" /nologo /fo \"%.*s.res\" \"%.*s.rc\"", + LIT(output_base), + LIT(build_context.resource_filepath) ); if (result) { @@ -297,13 +314,13 @@ i32 linker_stage(lbGenerator *gen) { } result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s \"%.*s\" -OUT:\"%.*s\" %s " + "\"%.*slink.exe\" %s \"%.*s.res\" -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename), + LIT(find_result.vs_exe_path), object_files, LIT(output_base), LIT(output_base), output_ext, link_settings, subsystem_str, LIT(build_context.link_flags), @@ -312,13 +329,13 @@ i32 linker_stage(lbGenerator *gen) { ); } else { result = system_exec_command_line_app("msvc-link", - "\"%.*slink.exe\" %s -OUT:\"%.*s\" %s " + "\"%.*slink.exe\" %s -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(vs_exe_path), object_files, LIT(output_filename), + LIT(find_result.vs_exe_path), object_files, LIT(output_base), output_ext, link_settings, subsystem_str, LIT(build_context.link_flags), @@ -333,13 +350,13 @@ i32 linker_stage(lbGenerator *gen) { } else { // lld result = system_exec_command_line_app("msvc-lld-link", - "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s " + "\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s.%s\" %s " "/nologo /incremental:no /opt:ref /subsystem:%s " " %.*s " " %.*s " " %s " "", - LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename), + LIT(build_context.ODIN_ROOT), object_files, LIT(output_base),output_ext, link_settings, subsystem_str, LIT(build_context.link_flags), @@ -398,7 +415,7 @@ i32 linker_stage(lbGenerator *gen) { } else if (string_ends_with(lib, str_lit(".so"))) { // dynamic lib, relative path to executable // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtime to the executable + // at runtimeto the executable lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); } else { // dynamic or static system lib, just link regularly searching system library paths @@ -414,6 +431,9 @@ i32 linker_stage(lbGenerator *gen) { object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path)); } + // Unlike the Win32 linker code, the output_ext includes the dot, because + // typically executable files on *NIX systems don't have extensions. + String output_ext = {}; gbString link_settings = gb_string_make_reserve(heap_allocator(), 32); if (build_context.no_crt) { @@ -441,12 +461,26 @@ i32 linker_stage(lbGenerator *gen) { // correctly this way since all the other dependencies provided implicitly // by the compiler frontend are still needed and most of the command // line arguments prepared previously are incompatible with ld. + // + // Shared libraries are .dylib on MacOS and .so on Linux. + if (build_context.metrics.os == TargetOs_darwin) { + output_ext = STR_LIT(".dylib"); + } else { + output_ext = STR_LIT(".so"); + } link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); } else if (build_context.metrics.os != TargetOs_openbsd) { // OpenBSD defaults to PIE executable. do not pass -no-pie for it. link_settings = gb_string_appendc(link_settings, "-no-pie "); } + if (build_context.out_filepath.len > 0) { + //NOTE(thebirk): We have a custom -out arguments, so we should use the extension from that + isize pos = string_extension_position(build_context.out_filepath); + if (pos > 0) { + output_ext = substring(build_context.out_filepath, pos, build_context.out_filepath.len); + } + } gbString platform_lib_str = gb_string_make(heap_allocator(), ""); defer (gb_string_free(platform_lib_str)); @@ -473,7 +507,7 @@ i32 linker_stage(lbGenerator *gen) { defer (gb_string_free(link_command_line)); link_command_line = gb_string_appendc(link_command_line, object_files); - link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s\" ", LIT(output_filename)); + link_command_line = gb_string_append_fmt(link_command_line, " -o \"%.*s%.*s\" ", LIT(output_base), LIT(output_ext)); link_command_line = gb_string_append_fmt(link_command_line, " %s ", platform_lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %s ", lib_str); link_command_line = gb_string_append_fmt(link_command_line, " %.*s ", LIT(build_context.link_flags)); @@ -490,7 +524,9 @@ i32 linker_stage(lbGenerator *gen) { if (build_context.ODIN_DEBUG) { // NOTE: macOS links DWARF symbols dynamically. Dsymutil will map the stubs in the exe // to the symbols in the object file - result = system_exec_command_line_app("dsymutil", "dsymutil %.*s", LIT(output_filename)); + result = system_exec_command_line_app("dsymutil", + "dsymutil %.*s%.*s", LIT(output_base), LIT(output_ext) + ); if (result) { return result; @@ -1490,10 +1526,6 @@ bool parse_build_flags(Array<String> args) { gb_printf_err("Invalid -resource path %.*s, missing .rc\n", LIT(path)); bad_flags = true; break; - } else if (!gb_file_exists((const char *)path.text)) { - gb_printf_err("Invalid -resource path %.*s, file does not exist.\n", LIT(path)); - bad_flags = true; - break; } build_context.resource_filepath = substring(path, 0, string_extension_position(path)); build_context.has_resource = true; @@ -1508,11 +1540,6 @@ bool parse_build_flags(Array<String> args) { String path = value.value_string; path = string_trim_whitespace(path); if (is_build_flag_path_valid(path)) { - if (path_is_directory(path)) { - gb_printf_err("Invalid -pdb-name path. %.*s, is a directory.\n", LIT(path)); - bad_flags = true; - break; - } // #if defined(GB_SYSTEM_WINDOWS) // String ext = path_extension(path); // if (ext != ".pdb") { @@ -2639,8 +2666,6 @@ int main(int arg_count, char const **arg_ptr) { return 1; } - init_filename = copy_string(permanent_allocator(), init_filename); - if (init_filename == "-help" || init_filename == "--help") { build_context.show_help = true; @@ -2663,12 +2688,6 @@ int main(int arg_count, char const **arg_ptr) { gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename)); gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n"); return 1; - } else { - String const ext = str_lit(".odin"); - if (!string_ends_with(init_filename, ext)) { - gb_printf_err("Expected either a directory or a .odin file, got '%.*s'\n", LIT(init_filename)); - return 1; - } } } } @@ -2690,24 +2709,13 @@ int main(int arg_count, char const **arg_ptr) { get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("shared"))); } + init_build_context(selected_target_metrics ? selected_target_metrics->metrics : nullptr); // if (build_context.word_size == 4 && build_context.metrics.os != TargetOs_js) { // print_usage_line(0, "%.*s 32-bit is not yet supported for this platform", LIT(args[0])); // return 1; // } - // Set and check build paths... - if (!init_build_paths(init_filename)) { - return 1; - } - - if (build_context.show_debug_messages) { - for_array(i, build_context.build_paths) { - String build_path = path_to_string(heap_allocator(), build_context.build_paths[i]); - debugf("build_paths[%ld]: %.*s\n", i, LIT(build_path)); - } - } - init_global_thread_pool(); defer (thread_pool_destroy(&global_thread_pool)); @@ -2724,8 +2732,6 @@ int main(int arg_count, char const **arg_ptr) { } defer (destroy_parser(parser)); - // TODO(jeroen): Remove the `init_filename` param. - // Let's put that on `build_context.build_paths[0]` instead. if (parse_packages(parser, init_filename) != ParseFile_None) { return 1; } @@ -2804,14 +2810,16 @@ int main(int arg_count, char const **arg_ptr) { } if (run_output) { - String exe_name = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Output]); - defer (gb_free(heap_allocator(), exe_name.text)); - #if defined(GB_SYSTEM_WINDOWS) - return system_exec_command_line_app("odin run", "%.*s %.*s", LIT(exe_name), LIT(run_args_string)); + return system_exec_command_line_app("odin run", "%.*s.exe %.*s", LIT(gen->output_base), LIT(run_args_string)); #else - return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(exe_name), LIT(run_args_string)); + //NOTE(thebirk): This whole thing is a little leaky + String output_ext = {}; + String complete_path = concatenate_strings(permanent_allocator(), gen->output_base, output_ext); + complete_path = path_to_full_path(permanent_allocator(), complete_path); + return system_exec_command_line_app("odin run", "\"%.*s\" %.*s", LIT(complete_path), LIT(run_args_string)); #endif } + return 0; } diff --git a/src/parser.cpp b/src/parser.cpp index df7f908a6..767119aa8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5751,7 +5751,7 @@ ParseFileError parse_packages(Parser *p, String init_filename) { } } } - + { // Add these packages serially and then process them parallel mutex_lock(&p->wait_mutex); diff --git a/src/path.cpp b/src/path.cpp deleted file mode 100644 index 8d8e532b8..000000000 --- a/src/path.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/*
- Path handling utilities.
-*/
-
-#if defined(GB_SYSTEM_WINDOWS)
- bool path_is_directory(String path) {
- gbAllocator a = heap_allocator();
- String16 wstr = string_to_string16(a, path);
- defer (gb_free(a, wstr.text));
-
- i32 attribs = GetFileAttributesW(wstr.text);
- if (attribs < 0) return false;
-
- return (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;
- }
-
-#else
- bool path_is_directory(String path) {
- gbAllocator a = heap_allocator();
- char *copy = cast(char *)copy_string(a, path).text;
- defer (gb_free(a, copy));
-
- struct stat s;
- if (stat(copy, &s) == 0) {
- return (s.st_mode & S_IFDIR) != 0;
- }
- return false;
- }
-#endif
-
-
-String path_to_full_path(gbAllocator a, String path) {
- gbAllocator ha = heap_allocator();
- char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
- defer (gb_free(ha, path_c));
-
- char *fullpath = gb_path_get_full_name(a, path_c);
- String res = string_trim_whitespace(make_string_c(fullpath));
-#if defined(GB_SYSTEM_WINDOWS)
- for (isize i = 0; i < res.len; i++) {
- if (res.text[i] == '\\') {
- res.text[i] = '/';
- }
- }
-#endif
- return copy_string(a, res);
-}
-
-struct Path {
- String basename;
- String name;
- String ext;
-};
-
-// NOTE(Jeroen): Naively turns a Path into a string.
-String path_to_string(gbAllocator a, Path path) {
- if (path.basename.len + path.name.len + path.ext.len == 0) {
- return make_string(nullptr, 0);
- }
-
- isize len = path.basename.len + 1 + path.name.len + 1;
- if (path.ext.len > 0) {
- len += path.ext.len + 1;
- }
-
- u8 *str = gb_alloc_array(a, u8, len);
-
- isize i = 0;
- gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len;
- gb_memmove(str+i, "/", 1); i += 1;
- gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len;
- if (path.ext.len > 0) {
- gb_memmove(str+i, ".", 1); i += 1;
- gb_memmove(str+i, path.ext.text, path.ext.len); i += path.ext.len;
- }
- str[i] = 0;
-
- String res = make_string(str, i);
- res = string_trim_whitespace(res);
- return res;
-}
-
-// NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`.
-String path_to_full_path(gbAllocator a, Path path) {
- String temp = path_to_string(heap_allocator(), path);
- defer (gb_free(heap_allocator(), temp.text));
-
- return path_to_full_path(a, temp);
-}
-
-// NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path,
-// and then breaks it into its components to make a Path.
-Path path_from_string(gbAllocator a, String const &path) {
- Path res = {};
-
- if (path.len == 0) return res;
-
- String fullpath = path_to_full_path(a, path);
- defer (gb_free(heap_allocator(), fullpath.text));
-
- res.basename = directory_from_path(fullpath);
- res.basename = copy_string(a, res.basename);
-
- if (string_ends_with(fullpath, '/')) {
- // It's a directory. We don't need to tinker with the name and extension.
- return res;
- }
-
- isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len;
- res.name = substring(fullpath, name_start, fullpath.len);
- res.name = remove_extension_from_path(res.name);
- res.name = copy_string(a, res.name);
-
- res.ext = path_extension(fullpath, false); // false says not to include the dot.
- res.ext = copy_string(a, res.ext);
- return res;
-}
-
-bool path_is_directory(Path path) {
- String path_string = path_to_full_path(heap_allocator(), path);
- defer (gb_free(heap_allocator(), path_string.text));
-
- return path_is_directory(path_string);
-}
-
-struct FileInfo {
- String name;
- String fullpath;
- i64 size;
- bool is_dir;
-};
-
-enum ReadDirectoryError {
- ReadDirectory_None,
-
- ReadDirectory_InvalidPath,
- ReadDirectory_NotExists,
- ReadDirectory_Permission,
- ReadDirectory_NotDir,
- ReadDirectory_Empty,
- ReadDirectory_Unknown,
-
- ReadDirectory_COUNT,
-};
-
-i64 get_file_size(String path) {
- char *c_str = alloc_cstring(heap_allocator(), path);
- defer (gb_free(heap_allocator(), c_str));
-
- gbFile f = {};
- gbFileError err = gb_file_open(&f, c_str);
- defer (gb_file_close(&f));
- if (err != gbFileError_None) {
- return -1;
- }
- return gb_file_size(&f);
-}
-
-
-#if defined(GB_SYSTEM_WINDOWS)
-ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
- GB_ASSERT(fi != nullptr);
-
- gbAllocator a = heap_allocator();
-
- while (path.len > 0) {
- Rune end = path[path.len-1];
- if (end == '/') {
- path.len -= 1;
- } else if (end == '\\') {
- path.len -= 1;
- } else {
- break;
- }
- }
-
- if (path.len == 0) {
- return ReadDirectory_InvalidPath;
- }
- {
- char *c_str = alloc_cstring(a, path);
- defer (gb_free(a, c_str));
-
- gbFile f = {};
- gbFileError file_err = gb_file_open(&f, c_str);
- defer (gb_file_close(&f));
-
- switch (file_err) {
- case gbFileError_Invalid: return ReadDirectory_InvalidPath;
- case gbFileError_NotExists: return ReadDirectory_NotExists;
- // case gbFileError_Permission: return ReadDirectory_Permission;
- }
- }
-
- if (!path_is_directory(path)) {
- return ReadDirectory_NotDir;
- }
-
-
- char *new_path = gb_alloc_array(a, char, path.len+3);
- defer (gb_free(a, new_path));
-
- gb_memmove(new_path, path.text, path.len);
- gb_memmove(new_path+path.len, "/*", 2);
- new_path[path.len+2] = 0;
-
- String np = make_string(cast(u8 *)new_path, path.len+2);
- String16 wstr = string_to_string16(a, np);
- defer (gb_free(a, wstr.text));
-
- WIN32_FIND_DATAW file_data = {};
- HANDLE find_file = FindFirstFileW(wstr.text, &file_data);
- if (find_file == INVALID_HANDLE_VALUE) {
- return ReadDirectory_Unknown;
- }
- defer (FindClose(find_file));
-
- array_init(fi, a, 0, 100);
-
- do {
- wchar_t *filename_w = file_data.cFileName;
- i64 size = cast(i64)file_data.nFileSizeLow;
- size |= (cast(i64)file_data.nFileSizeHigh) << 32;
- String name = string16_to_string(a, make_string16_c(filename_w));
- if (name == "." || name == "..") {
- gb_free(a, name.text);
- continue;
- }
-
- String filepath = {};
- filepath.len = path.len+1+name.len;
- filepath.text = gb_alloc_array(a, u8, filepath.len+1);
- defer (gb_free(a, filepath.text));
- gb_memmove(filepath.text, path.text, path.len);
- gb_memmove(filepath.text+path.len, "/", 1);
- gb_memmove(filepath.text+path.len+1, name.text, name.len);
-
- FileInfo info = {};
- info.name = name;
- info.fullpath = path_to_full_path(a, filepath);
- info.size = size;
- info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
- array_add(fi, info);
- } while (FindNextFileW(find_file, &file_data));
-
- if (fi->count == 0) {
- return ReadDirectory_Empty;
- }
-
- return ReadDirectory_None;
-}
-#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
-
-#include <dirent.h>
-
-ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
- GB_ASSERT(fi != nullptr);
-
- gbAllocator a = heap_allocator();
-
- char *c_path = alloc_cstring(a, path);
- defer (gb_free(a, c_path));
-
- DIR *dir = opendir(c_path);
- if (!dir) {
- switch (errno) {
- case ENOENT:
- return ReadDirectory_NotExists;
- case EACCES:
- return ReadDirectory_Permission;
- case ENOTDIR:
- return ReadDirectory_NotDir;
- default:
- // ENOMEM: out of memory
- // EMFILE: per-process limit on open fds reached
- // ENFILE: system-wide limit on total open files reached
- return ReadDirectory_Unknown;
- }
- GB_PANIC("unreachable");
- }
-
- array_init(fi, a, 0, 100);
-
- for (;;) {
- struct dirent *entry = readdir(dir);
- if (entry == nullptr) {
- break;
- }
-
- String name = make_string_c(entry->d_name);
- if (name == "." || name == "..") {
- continue;
- }
-
- String filepath = {};
- filepath.len = path.len+1+name.len;
- filepath.text = gb_alloc_array(a, u8, filepath.len+1);
- defer (gb_free(a, filepath.text));
- gb_memmove(filepath.text, path.text, path.len);
- gb_memmove(filepath.text+path.len, "/", 1);
- gb_memmove(filepath.text+path.len+1, name.text, name.len);
- filepath.text[filepath.len] = 0;
-
-
- struct stat dir_stat = {};
-
- if (stat((char *)filepath.text, &dir_stat)) {
- continue;
- }
-
- if (S_ISDIR(dir_stat.st_mode)) {
- continue;
- }
-
- i64 size = dir_stat.st_size;
-
- FileInfo info = {};
- info.name = name;
- info.fullpath = path_to_full_path(a, filepath);
- info.size = size;
- array_add(fi, info);
- }
-
- if (fi->count == 0) {
- return ReadDirectory_Empty;
- }
-
- return ReadDirectory_None;
-}
-#else
-#error Implement read_directory
-#endif
-
diff --git a/src/string.cpp b/src/string.cpp index 3515df48e..d3dbc6904 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -245,14 +245,15 @@ gb_inline isize string_extension_position(String const &str) { return dot_pos; } -String path_extension(String const &str, bool include_dot = true) { +String path_extension(String const &str) { isize pos = string_extension_position(str); if (pos < 0) { return make_string(nullptr, 0); } - return substring(str, include_dot ? pos : pos + 1, str.len); + return substring(str, pos, str.len); } + String string_trim_whitespace(String str) { while (str.len > 0 && rune_is_whitespace(str[str.len-1])) { str.len--; @@ -327,10 +328,7 @@ String directory_from_path(String const &s) { break; } } - if (i >= 0) { - return substring(s, 0, i); - } - return substring(s, 0, 0); + return substring(s, 0, i); } String concatenate_strings(gbAllocator a, String const &x, String const &y) { |