浏览代码

Support subtargets in build tags: `#build darwin:generic` and `#build linux:android, darwin:ios`

gingerBill 5 月之前
父节点
当前提交
1f814c33dc
共有 5 个文件被更改,包括 138 次插入13 次删除
  1. 4 0
      base/runtime/core.odin
  2. 19 5
      core/odin/parser/file_tags.odin
  3. 30 4
      src/build_settings.cpp
  4. 8 4
      src/parser.cpp
  5. 77 0
      src/string.cpp

+ 4 - 0
base/runtime/core.odin

@@ -559,10 +559,14 @@ ALL_ODIN_OS_TYPES :: Odin_OS_Types{
 	Odin_Platform_Subtarget_Type :: enum int {
 		Default,
 		iOS,
+		Android,
 	}
 */
 Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
 
+Odin_Platform_Subtarget_Types :: bit_set[Odin_Platform_Subtarget_Type]
+
+
 /*
 	// Defined internally by the compiler
 	Odin_Sanitizer_Flag :: enum u32 {

+ 19 - 5
core/odin/parser/file_tags.odin

@@ -30,14 +30,27 @@ File_Tags :: struct {
 }
 
 @require_results
-get_build_os_from_string :: proc(str: string) -> runtime.Odin_OS_Type {
+get_build_os_from_string :: proc(str: string) -> (found_os: runtime.Odin_OS_Type, found_subtarget: runtime.Odin_Platform_Subtarget_Type) {
+	str_os, _, str_subtarget := strings.partition(str, ":")
+
 	fields := reflect.enum_fields_zipped(runtime.Odin_OS_Type)
 	for os in fields {
-		if strings.equal_fold(os.name, str) {
-			return runtime.Odin_OS_Type(os.value)
+		if strings.equal_fold(os.name, str_os) {
+			found_os = runtime.Odin_OS_Type(os.value)
+			break
 		}
 	}
-	return .Unknown
+	if str_subtarget != "" {
+		fields := reflect.enum_fields_zipped(runtime.Odin_Platform_Subtarget_Type)
+		for subtarget in fields {
+			if strings.equal_fold(subtarget.name, str_subtarget) {
+				found_subtarget = runtime.Odin_Platform_Subtarget_Type(subtarget.value)
+				break
+			}
+		}
+	}
+
+	return
 }
 @require_results
 get_build_arch_from_string :: proc(str: string) -> runtime.Odin_Arch_Type {
@@ -187,7 +200,8 @@ parse_file_tags :: proc(file: ast.File, allocator := context.allocator) -> (tags
 
 						if value == "ignore" {
 							tags.ignore = true
-						} else if os := get_build_os_from_string(value); os != .Unknown {
+						} else if os, subtarget := get_build_os_from_string(value); os != .Unknown {
+							_ = subtarget // TODO(bill): figure out how to handle the subtarget logic
 							if is_notted {
 								os_negative += {os}
 							} else {

+ 30 - 4
src/build_settings.cpp

@@ -847,13 +847,39 @@ gb_global NamedTargetMetrics *selected_target_metrics;
 gb_global Subtarget selected_subtarget;
 
 
-gb_internal TargetOsKind get_target_os_from_string(String str) {
+gb_internal TargetOsKind get_target_os_from_string(String str, Subtarget *subtarget_ = nullptr) {
+	String os_name = str;
+	String subtarget = {};
+	auto part = string_partition(str, str_lit(":"));
+	if (part.match.len == 1) {
+		os_name = part.head;
+		subtarget = part.tail;
+	}
+
+	TargetOsKind kind = TargetOs_Invalid;
+
 	for (isize i = 0; i < TargetOs_COUNT; i++) {
-		if (str_eq_ignore_case(target_os_names[i], str)) {
-			return cast(TargetOsKind)i;
+		if (str_eq_ignore_case(target_os_names[i], os_name)) {
+			kind = cast(TargetOsKind)i;
+			break;
 		}
 	}
-	return TargetOs_Invalid;
+	if (subtarget_) *subtarget_ = Subtarget_Default;
+
+	if (subtarget.len != 0) {
+		if (str_eq_ignore_case(subtarget, "generic") || str_eq_ignore_case(subtarget, "default")) {
+			if (subtarget_) *subtarget_ = Subtarget_Default;
+		} else {
+			for (isize i = 1; i < Subtarget_COUNT; i++) {
+				if (str_eq_ignore_case(subtarget_strings[i], subtarget)) {
+					if (subtarget_) *subtarget_ = cast(Subtarget)i;
+					break;
+				}
+			}
+		}
+	}
+
+	return kind;
 }
 
 gb_internal TargetArchKind get_target_arch_from_string(String str) {

+ 8 - 4
src/parser.cpp

@@ -6157,7 +6157,7 @@ gb_internal String build_tag_get_token(String s, String *out) {
 		isize width = utf8_decode(&s[n], s.len-n, &rune);
 		if (n == 0 && rune == '!') {
 
-		} else if (!rune_is_letter(rune) && !rune_is_digit(rune)) {
+		} else if (!rune_is_letter(rune) && !rune_is_digit(rune) && rune != ':') {
 			isize k = gb_max(gb_max(n, width), 1);
 			*out = substring(s, k, s.len);
 			return substring(s, 0, k);
@@ -6209,7 +6209,9 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
 				continue;
 			}
 
-			TargetOsKind   os   = get_target_os_from_string(p);
+			Subtarget subtarget = Subtarget_Default;
+
+			TargetOsKind   os   = get_target_os_from_string(p, &subtarget);
 			TargetArchKind arch = get_target_arch_from_string(p);
 			num_tokens += 1;
 
@@ -6223,11 +6225,13 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) {
 			if (os != TargetOs_Invalid) {
 				this_kind_os_seen = true;
 
+				bool same_subtarget = (subtarget == Subtarget_Default) || (subtarget == selected_subtarget);
+
 				GB_ASSERT(arch == TargetArch_Invalid);
 				if (is_notted) {
-					this_kind_correct = this_kind_correct && (os != build_context.metrics.os);
+					this_kind_correct = this_kind_correct && (os != build_context.metrics.os || !same_subtarget);
 				} else {
-					this_kind_correct = this_kind_correct && (os == build_context.metrics.os);
+					this_kind_correct = this_kind_correct && (os == build_context.metrics.os && same_subtarget);
 				}
 			} else if (arch != TargetArch_Invalid) {
 				this_kind_arch_seen = true;

+ 77 - 0
src/string.cpp

@@ -336,6 +336,83 @@ gb_internal Array<String> split_lines_from_array(Array<u8> const &array, gbAlloc
 	return lines;
 }
 
+enum : u32 { PRIME_RABIN_KARP = 16777619u };
+
+gb_internal u32 hash_str_rabin_karp(String const &s, u32 *pow_) {
+	u32 hash = 0;
+	u32 pow = 1;
+	for (isize i = 0; i < s.len; i++) {
+		hash = hash*PRIME_RABIN_KARP + cast(u32)s.text[i];
+	}
+	u32 sq = PRIME_RABIN_KARP;
+	for (isize i = s.len; i > 0; i >>= 1) {
+		if ((i & 1) != 0) {
+			pow *= sq;
+		}
+		sq *= sq;
+	}
+	if (pow_) *pow_ = pow;
+	return hash;
+
+}
+
+
+gb_internal isize string_index(String const &s, String const &substr) {
+	isize n = substr.len;
+	if (n == 0) {
+		return 0;
+	} else if (n == 1) {
+		return string_index_byte(s, substr[0]);
+	} else if (n == s.len) {
+		if (s == substr) {
+			return 0;
+		}
+		return -1;
+	} else if (n > s.len) {
+		return -1;
+	}
+	u32 pow = 1;
+	u32 hash = hash_str_rabin_karp(s, &pow);
+	u32 h = 0;
+	for (isize i = 0; i < n; i++) {
+		h = h*PRIME_RABIN_KARP + cast(u32)s.text[i];
+	}
+	if (h == hash && substring(s, 0, n) == substr) {
+		return 0;
+	}
+	for (isize i = n; i < s.len; /**/) {
+		h *= PRIME_RABIN_KARP;
+		h += cast(u32)s.text[i];
+		h -= pow * u32(s.text[i-n]);
+		i += 1;
+		if (h == hash && substring(s, i-n, i) == substr) {
+			return i - n;
+		}
+	}
+	return -1;
+}
+
+
+struct StringPartition {
+	String head;
+	String match;
+	String tail;
+};
+
+gb_internal StringPartition string_partition(String const &str, String const &sep) {
+	StringPartition res = {};
+	isize i = string_index(str, sep);
+	if (i < 0) {
+		res.head = str;
+		return res;
+	}
+
+	res.head  = substring(str, 0, i);
+	res.match = substring(str, i, i+sep.len);
+	res.tail  = substring(str, i+sep.len, str.len);
+	return res;
+}
+
 gb_internal bool string_contains_char(String const &s, u8 c) {
 	isize i;
 	for (i = 0; i < s.len; i++) {