@@ -24,13 +24,113 @@ import("lib.detect.find_tool")
2424import (" private.core.base.is_cross" )
2525import (" package.manager.pkgconfig.find_package" , {alias = " find_package_from_pkgconfig" })
2626
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+
27115-- get all nix store paths currently available in environment
28116function _get_available_nix_paths ()
29117 local paths = {}
30118 local seen = {}
31119
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)
33132 local env_path = os.getenv (" PATH" ) or " "
133+
34134 for dir in env_path :gmatch (" [^:]+" ) do
35135 if dir :startswith (" /nix/store/" ) then
36136 local store_path = dir :match (" (/nix/store/[^/]+)" )
@@ -46,11 +146,12 @@ function _get_available_nix_paths()
46146 os.getenv (" NIX_PROFILES" ) or " " ,
47147 (os.getenv (" HOME" ) or " " ) .. " /.nix-profile" ,
48148 " /nix/var/nix/profiles/default" ,
49- " /run/current-system/sw" -- NixOS system packages
149+ " /run/current-system/sw" -- NixOS
50150 }
51151
52152 for _ , location in ipairs (env_locations ) do
53153 if location ~= " " and os .isdir (location ) then
154+
54155 -- Check if it's a symlink to store path
55156 local target = try {function ()
56157 return os .iorunv (" readlink" , {" -f" , location }):trim ()
@@ -81,16 +182,64 @@ function _get_available_nix_paths()
81182 end
82183 end
83184 end
84-
185+
85186 return paths
86187end
87188
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
89232function _find_in_store_path (store_path , name )
233+
90234 if not os .isdir (store_path ) then
91235 return nil
92236 end
93237
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+
94243 local result = {}
95244
96245 -- Find include directories
@@ -106,7 +255,7 @@ function _find_in_store_path(store_path, name)
106255 result .links = {}
107256 result .libfiles = {}
108257
109- -- Scan for library files
258+ -- Scan for library files related to our package
110259 local libfiles = os .files (path .join (libdir , " *.so*" ),
111260 path .join (libdir , " *.a" ),
112261 path .join (libdir , " *.dylib*" ))
@@ -118,8 +267,10 @@ function _find_in_store_path(store_path, name)
118267 filename :match (" ^lib(.+)%.dylib" )
119268
120269 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
123274
124275 if filename :endswith (" .a" ) then
125276 result .static = true
@@ -151,7 +302,7 @@ function _find_in_store_path(store_path, name)
151302 end
152303
153304 -- 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
155306 return result
156307 end
157308
@@ -208,9 +359,9 @@ function main(name, opt)
208359 -- Get all available Nix store paths
209360 local nix_paths = _get_available_nix_paths ()
210361
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
214365 local result = _find_in_store_path (store_path , actual_name )
215366 if result then
216367 if opt .verbose or option .get (" verbose" ) then
@@ -221,24 +372,26 @@ function main(name, opt)
221372 end
222373 end
223374
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
240394 end
241- return result
242395 end
243396 end
244397
0 commit comments