@@ -24,13 +24,113 @@ import("lib.detect.find_tool")
24
24
import (" private.core.base.is_cross" )
25
25
import (" package.manager.pkgconfig.find_package" , {alias = " find_package_from_pkgconfig" })
26
26
27
+ -- check if we're in a nix-shell environment
28
+ function _in_nix_shell ()
29
+ local in_nix_shell = os.getenv (" IN_NIX_SHELL" )
30
+ return in_nix_shell == " pure" or in_nix_shell == " impure"
31
+ end
32
+
33
+ -- extract store paths from nix environment variables with better filtering
34
+ function _extract_nix_store_paths (env_var_name , env_var_value )
35
+ local paths = {}
36
+ local seen = {}
37
+
38
+ if env_var_value == " " then
39
+ return paths
40
+ end
41
+
42
+ -- Handle different environment variable formats
43
+ local separators = {
44
+ PATH = " :" ,
45
+ PKG_CONFIG_PATH = " :" ,
46
+ LIBRARY_PATH = " :" ,
47
+ LD_LIBRARY_PATH = " :" ,
48
+ C_INCLUDE_PATH = " :" ,
49
+ CPLUS_INCLUDE_PATH = " :" ,
50
+ NIX_LDFLAGS = " %s" , -- space separated, may contain -L flags
51
+ NIX_CFLAGS_COMPILE = " %s" -- space separated, may contain -I flags
52
+ }
53
+
54
+ local separator = separators [env_var_name ] or " :"
55
+ local pattern = separator == " :" and " [^:]+" or " [^%s]+"
56
+
57
+ for item in env_var_value :gmatch (pattern ) do
58
+ local clean_item = item
59
+
60
+ -- Remove flag prefixes for compiler/linker flags
61
+ if env_var_name == " NIX_LDFLAGS" then
62
+ clean_item = item :gsub (" ^%-L" , " " )
63
+ elseif env_var_name == " NIX_CFLAGS_COMPILE" then
64
+ clean_item = item :gsub (" ^%-[iI]system%s*" , " " ):gsub (" ^%-I" , " " )
65
+ end
66
+
67
+ if clean_item :startswith (" /nix/store/" ) then
68
+ local store_path = clean_item :match (" (/nix/store/[^/]+)" )
69
+ if store_path and not seen [store_path ] then
70
+ seen [store_path ] = true
71
+ table.insert (paths , store_path )
72
+ end
73
+ end
74
+ end
75
+
76
+ return paths
77
+ end
78
+
79
+ -- get current shell buildInputs from environment with improved detection
80
+ function _get_shell_build_inputs ()
81
+ local all_paths = {}
82
+ local seen = {}
83
+
84
+ if not _in_nix_shell () then
85
+ return all_paths
86
+ end
87
+
88
+ -- Environment variables to check for nix store paths
89
+ local env_vars = {
90
+ " PATH" ,
91
+ " PKG_CONFIG_PATH" ,
92
+ " LIBRARY_PATH" ,
93
+ " LD_LIBRARY_PATH" ,
94
+ " C_INCLUDE_PATH" ,
95
+ " CPLUS_INCLUDE_PATH" ,
96
+ " NIX_LDFLAGS" ,
97
+ " NIX_CFLAGS_COMPILE"
98
+ }
99
+
100
+ for _ , env_var in ipairs (env_vars ) do
101
+ local env_value = os.getenv (env_var ) or " "
102
+ local paths = _extract_nix_store_paths (env_var , env_value )
103
+
104
+ for _ , path in ipairs (paths ) do
105
+ if not seen [path ] then
106
+ seen [path ] = true
107
+ table.insert (all_paths , path )
108
+ end
109
+ end
110
+ end
111
+
112
+ return all_paths
113
+ end
114
+
27
115
-- get all nix store paths currently available in environment
28
116
function _get_available_nix_paths ()
29
117
local paths = {}
30
118
local seen = {}
31
119
32
- -- Get paths from environment PATH
120
+ -- First, get paths from current shell if we're in nix-shell
121
+ if _in_nix_shell () then
122
+ local shell_paths = _get_shell_build_inputs ()
123
+ for _ , path in ipairs (shell_paths ) do
124
+ if not seen [path ] then
125
+ seen [path ] = true
126
+ table.insert (paths , path )
127
+ end
128
+ end
129
+ end
130
+
131
+ -- Get paths from environment PATH (additional check)
33
132
local env_path = os.getenv (" PATH" ) or " "
133
+
34
134
for dir in env_path :gmatch (" [^:]+" ) do
35
135
if dir :startswith (" /nix/store/" ) then
36
136
local store_path = dir :match (" (/nix/store/[^/]+)" )
@@ -46,11 +146,12 @@ function _get_available_nix_paths()
46
146
os.getenv (" NIX_PROFILES" ) or " " ,
47
147
(os.getenv (" HOME" ) or " " ) .. " /.nix-profile" ,
48
148
" /nix/var/nix/profiles/default" ,
49
- " /run/current-system/sw" -- NixOS system packages
149
+ " /run/current-system/sw" -- NixOS
50
150
}
51
151
52
152
for _ , location in ipairs (env_locations ) do
53
153
if location ~= " " and os .isdir (location ) then
154
+
54
155
-- Check if it's a symlink to store path
55
156
local target = try {function ()
56
157
return os .iorunv (" readlink" , {" -f" , location }):trim ()
@@ -81,16 +182,64 @@ function _get_available_nix_paths()
81
182
end
82
183
end
83
184
end
84
-
185
+
85
186
return paths
86
187
end
87
188
88
- -- find package in a specific nix store path
189
+ -- check if a store path actually contains the requested package
190
+ function _validate_package_in_store_path (store_path , name )
191
+
192
+ -- Check if the store path name contains the package name
193
+ local store_name = path .basename (store_path ):lower ()
194
+ local search_name = name :lower ()
195
+
196
+ -- Look for exact match, or package name in the store path
197
+ local name_match = store_name :find (search_name , 1 , true ) or
198
+ store_name :find ((search_name :gsub (" %-" , " %%-" ))) -- handle hyphens
199
+
200
+ if name_match then
201
+ return true
202
+ end
203
+
204
+ -- Check for libraries with the package name
205
+ local libdir = path .join (store_path , " lib" )
206
+ if os .isdir (libdir ) then
207
+ local libfiles = os .files (path .join (libdir , " lib" .. name .. " .*" ))
208
+ if # libfiles > 0 then
209
+ return true
210
+ end
211
+ end
212
+
213
+ -- Check for pkg-config files
214
+ local pkgconfigdirs = {
215
+ path .join (store_path , " lib" , " pkgconfig" ),
216
+ path .join (store_path , " share" , " pkgconfig" )
217
+ }
218
+
219
+ for _ , pcdir in ipairs (pkgconfigdirs ) do
220
+ if os .isdir (pcdir ) then
221
+ local pcfiles = os .files (path .join (pcdir , name .. " .pc" ))
222
+ if # pcfiles > 0 then
223
+ return true
224
+ end
225
+ end
226
+ end
227
+
228
+ return false
229
+ end
230
+
231
+ -- find package in a specific nix store path with validation
89
232
function _find_in_store_path (store_path , name )
233
+
90
234
if not os .isdir (store_path ) then
91
235
return nil
92
236
end
93
237
238
+ -- First validate that this store path actually contains our package
239
+ if not _validate_package_in_store_path (store_path , name ) then
240
+ return nil
241
+ end
242
+
94
243
local result = {}
95
244
96
245
-- Find include directories
@@ -106,7 +255,7 @@ function _find_in_store_path(store_path, name)
106
255
result .links = {}
107
256
result .libfiles = {}
108
257
109
- -- Scan for library files
258
+ -- Scan for library files related to our package
110
259
local libfiles = os .files (path .join (libdir , " *.so*" ),
111
260
path .join (libdir , " *.a" ),
112
261
path .join (libdir , " *.dylib*" ))
@@ -118,8 +267,10 @@ function _find_in_store_path(store_path, name)
118
267
filename :match (" ^lib(.+)%.dylib" )
119
268
120
269
if linkname then
121
- table.insert (result .links , linkname )
122
- table.insert (result .libfiles , libfile )
270
+ if linkname == name or linkname :find (name , 1 , true ) then
271
+ table.insert (result .links , linkname )
272
+ table.insert (result .libfiles , libfile )
273
+ end
123
274
124
275
if filename :endswith (" .a" ) then
125
276
result .static = true
@@ -151,7 +302,7 @@ function _find_in_store_path(store_path, name)
151
302
end
152
303
153
304
-- Return result if we found anything useful
154
- if result .includedirs or result .linkdirs then
305
+ if result .includedirs or ( result .links and # result . links > 0 ) then
155
306
return result
156
307
end
157
308
@@ -208,9 +359,9 @@ function main(name, opt)
208
359
-- Get all available Nix store paths
209
360
local nix_paths = _get_available_nix_paths ()
210
361
211
- -- Search through available paths first (unless we're forced to build )
212
- if # nix_paths > 0 and not force_nix then
213
- for _ , store_path in ipairs (nix_paths ) do
362
+ -- Search through available paths first (prioritize shell environment )
363
+ if # nix_paths > 0 then
364
+ for i , store_path in ipairs (nix_paths ) do
214
365
local result = _find_in_store_path (store_path , actual_name )
215
366
if result then
216
367
if opt .verbose or option .get (" verbose" ) then
@@ -221,24 +372,26 @@ function main(name, opt)
221
372
end
222
373
end
223
374
224
- -- If not found in available paths or forced to build, try building
225
- local storepath = nil
226
-
227
- -- Try modern nix first
228
- storepath = _try_modern_nix_build (actual_name )
229
-
230
- -- Fallback to legacy nix-build
231
- if not storepath then
232
- storepath = _try_legacy_nix_build (actual_name )
233
- end
234
-
235
- if storepath and os .isdir (storepath ) then
236
- local result = _find_in_store_path (storepath , actual_name )
237
- if result then
238
- if opt .verbose or option .get (" verbose" ) then
239
- print (" Built and found " .. actual_name .. " in: " .. storepath )
375
+ -- If not found in available paths and not in nix-shell, try building
376
+ if not _in_nix_shell () or force_nix then
377
+ local storepath = nil
378
+
379
+ -- Try modern nix first
380
+ storepath = _try_modern_nix_build (actual_name )
381
+
382
+ -- Fallback to legacy nix-build
383
+ if not storepath then
384
+ storepath = _try_legacy_nix_build (actual_name )
385
+ end
386
+
387
+ if storepath and os .isdir (storepath ) then
388
+ local result = _find_in_store_path (storepath , actual_name )
389
+ if result then
390
+ if opt .verbose or option .get (" verbose" ) then
391
+ print (" Built and found " .. actual_name .. " in: " .. storepath )
392
+ end
393
+ return result
240
394
end
241
- return result
242
395
end
243
396
end
244
397
0 commit comments